FC2ブログ

CSVの自力解釈 


CSV 云々に関しては、過去記事「テキストファイル(CSV等)の項目変換」とか・・・
処理内容については細かく記述してませんでしたね。

まぁ、あのツールもいろんなパターンを処理しきれているわけでもないので・・・
ソコソコ使ってみて、使えるようなら使うという事で・・・

今回、関数として作成したので、
・そのままでも・・・
・部分的にでも・・・

1行だけでも、複数行でもソコソコ処理できているんじゃないかな・・・と思ってみたり
内部の処理パターンは2種で
・Split で分けながら " " で囲まれた中での改行判別・・・とか
・InStr を多用して、文字列を切り出していく・・・とか

Private Function PartsInLines(sBuf As String, Optional sSep As String = ",") As Variant

っていう主処理部分に皮をかぶせて
Public Function PartsInLinesCSV(sBuf As String) As Variant
  PartsInLinesCSV = PartsInLines(sBuf)
End Function

Public Function PartsInLinesTAB(sBuf As String) As Variant
  PartsInLinesTAB = PartsInLines(sBuf, vbTab)
End Function

Public Function PartsInLinesSPACE(sBuf As String) As Variant
  PartsInLinesSPACE = PartsInLines(sBuf, " ")
End Function

これの呼び出し方は、(以下は Excel での例ですが、Access でも・・・)
(ソコソコの大きさのファイルなら以下で大丈夫だと思います)
Public Sub testReadGet()
  Dim ffn As Integer
  Dim v As Variant
  Dim btBuf() As Byte, sBuf As String
  Dim i As Long, j As Long

  ffn = FreeFile()
  Open ThisWorkbook.Path & "\ファイル名.csv" For Binary As #ffn
  ReDim btBuf(1 To LOF(ffn))
  Get #ffn, , btBuf
  Close #ffn
  sBuf = StrConv(btBuf, vbUnicode)

  v = PartsInLinesCSV(sBuf)
  Debug.Print sBuf
  For i = LBound(v) To UBound(v)
    For j = LBound(v(i)) To UBound(v(i))
      Debug.Print i; "."; j; " > "; v(i)(j)
    Next
  Next
End Sub

ファイルがかなり大きくて、1行ずつの処理が良いなら
Public Sub testReadLine()
  Dim ffn As Integer
  Dim v As Variant
  Dim sBuf As String
  Dim i As Long, j As Long

  ffn = FreeFile()
  Open ThisWorkbook.Path & "\ファイル名.csv" For Input As #ffn
  While (Not EOF(ffn))
    Line Input #ffn, sBuf

    v = PartsInLinesCSV(sBuf)
    Debug.Print sBuf
    For i = LBound(v) To UBound(v)
      For j = LBound(v(i)) To UBound(v(i))
        Debug.Print i; "."; j; " > "; v(i)(j)
      Next
    Next
  Wend
  Close #ffn
End Sub

    For i = LBound(v) To UBound(v)
部分は、1行分しか解釈させていないので v(0) 固定でも・・・
でも、でも・・・解釈できない場合は、空配列を返すので、固定はまずいかも・・・
戻り値は、Variant の配列で
・UBound(v)+1 で何行ありますよ( LBound(v) は 0 なんだけど一応・・・・)
・で、v(i)(0 ~ xx) がその行で切り出した項目(文字列 String で返します)
ってなものになってます。

仕様という程のものでは・・・・以下を処理します。
区切りを , とした場合

・文字列の囲みは、 " " および ' ' を自動認識
 また、囲みの文字が抜き出した文字列内にあったら、2個→1個に
"A,BC""DEF",'a,bc''def',1234 とか "A,BC""DEF" , 'a,bc''def' , 1234

(0)A,BC"DEF
(1)a,bc'def
(2)1234

・文字列の囲み以外の " および ' はそのまま
"A,B''C""DEF",'a,b""c''def',1234 とか "A,B''C""DEF" , 'a,b""c''def' , 1234

(0)A,B''C"DEF
(1)a,b""c'def
(2)1234

・囲み文字内の改行は項目内の文字列に入れる
・各行の項目数が違っていても合わせる事はしない
・項目は全て文字列として返す
続きを読んでみようかな ---≫
スポンサーサイト

2015/03/06

Category: 関数を作ってみる

TB: --  /  CM: 0

top △

Excelシート名を得る 


質問者さんには不評だったものもありますが・・・・ (広告表示も間近なので)

CreateObject("Excel.Application") してからファイルをオープンして・・・
って例題もいっぱいあるし・・・似たようなものも過去記事にあるし・・・で

不慣れな以下2つを記述しておこうかと・・・・

・GetObject を使って
・ADODB の OpenSchema を使って

なお、これらの方法は Runtime 環境でもいけると思います。

ただし難点が・・・ 確認した環境は、Vista+2007 なのですが、
OpenSchema でやった場合、確認していた拡張子が xlsm ファイルでしたけど・・・
Excel ファイルの更新日時が変わっちゃうんですね・・・実行した時刻に・・・・
Excel ファイルの更新日時を見ながら何かしている状況では使えないかな?
他の拡張子ではどうなるんだろう??

ただね・・・ OpenSchema の方が速いんだよね・・・ GetObject より・・・
また、何らかのエラーがあっても Excel がゾンビっぽくならないし・・・
続きを読んでみようかな ---≫

2014/10/26

Category: 関数を作ってみる

TB: --  /  CM: 0

top △

"mmdd" を Date 型に変換する関数 


どこだったか・・・ 最近の質問で見かけたんですけど

"mmdd" を Date 型に変換する関数を作ってみました。
"mmdd" だけではなく、
 "yymmdd" とか、"yymd" とか・・・・色々対応できるように

関数名は Str2Date で、戻り値は基本 Date 型(日付と解釈できない場合は Empty)
なので、戻り値の型は Variant としています。

引数は3つあって
第1引数(必須): "mmdd" 等の変換元文字列
第2引数(オプション):第1引数の先頭に付けて解釈する
第3引数(オプション):年、月、日を解釈する文字数

関数内部では、年、月、日を解釈する文字数を以下で定義していますが
  iA(0) = 0 ' 年用文字数
  iA(1) = 2
  iA(2) = 2
第3引数で指定されたもので上書き更新します。
第3引数が、3 であれば、(3, 2, 2)
第3引数が、Array(4, 2, 2) であれば、(4, 2, 2)
第3引数が、Array(4, 1) であれば、(4, 1, 2)
Array で指定する順は、年、月、日で・・・

第1引数で指定された文字列は、日、月、年 の順で、文字列右側から切り取っていきます。
年 部分先頭に第2引数を付加しますが、最終的に、年が生成されていなかったら今の年を・・・
これら切り取ったもので作った文字列が日付か??・・・
日付なら、Date 型を戻します。

以下の様な感じで利用します。
得られる日付記   述
2014/10/25 Str2Date("1025")
   年の指定が無いので今年の・・・
2014/10/25 Str2Date("251025")
   文字列に年部分はあるけど、解釈は (0, 2, 2) なので
   今年の・・・
2013/10/25 Str2Date("1025", "H25")
   元の文字列には年はないけど・・・
2013/10/25 Str2Date("1025", "2013")
   元の文字列には年はないけど・・・
2014/10/25 Str2Date("141025", , Array(2, 2, 2))
   年、月、日解釈を、各2文字づつで・・・
2014/10/25 Str2Date("141025", , 2)
   年部分を2文字としてね・・・
   月、日部分は、従来通り各2文字でね・・・
2014/10/25 Str2Date("261025", "H", 2)
   年部分を2文字として・・・・
   年の解釈先頭に "H" を付けてね・・・
1951/10/25 Str2Date("261025", "S", 2)
   年部分を2文字として・・・・
   年の解釈先頭に "S" を付けてね・・・
1893/10/25 Str2Date("261025", "M", 2)
   年部分を2文字として・・・・
   年の解釈先頭に "M" を付けてね・・・
2010/02/05 Str2Date("1025", , Array(2, 1, 1))
   年の解釈を2文字、月、日は1文字でね
1998/02/05 Str2Date("1025", "平成", Array(2, 1, 1))
   年の解釈を2文字、月、日は1文字でね
   そして、年の先頭に "平成" を付けてね・・・・
2014/10/25 Str2Date("H261025", , 3)
   年の解釈を3文字で、月、日は従来通り2文字でね
2014/01/25 Str2Date("H26125", , Array(3, 1))
   年の解釈を3文字、月を1文字、日は従来通り2文字でね

続きを読んでみようかな ---≫

2014/09/21

Category: 関数を作ってみる

TB: --  /  CM: 0

top △

数値を漢数字へ 


数値: 12345

とあったら 一万二千三百四十五

に変換したい。

こんな関数を考えてみました。

関数名: CnvKanNum

第一引数: 長整数 (変換したい数値)
第二引数(省略時=0): 解釈桁数(0 を何個付加するか)
第三引数(省略時=False): 文字列先頭が千の位の一であった場合、一を削除するか

CnvKanNum(1234) の場合:     一千二百三十四
CnvKanNum(1234,,True) の場合:   千二百三十四
CnvKanNum(1234,3) の場合:     百二十三万四千
CnvKanNum(1234,4,False) の場合: 一千二百三十四万
CnvKanNum(1234,4,True) の場合:   千二百三十四万
続きを読んでみようかな ---≫

2012/05/19

Category: 関数を作ってみる

TB: 0  /  CM: 0

top △

文字の並べ替え 


"201-20 201-1  202-2 202-11 1011 235 20" という文字列があった時、
空白を区切りとして、各文字列を並べ替えたい・・・・

これ、単純に並べ替えると
"1011 20 201-1 201-20 202-11 202-2 235" の様になりますが
"20 201-1 201-20 202-2 202-11 235 1011" の様に数値として解釈した結果で並び替えたい。

数値として解釈する際、"-" の区切りが1つ存在する場合がある。
この時に、"-" がある場合には、左側のもの・・・  "-" がない場合は、そのままで・・・

また、"-" があった場合の右側についても数値として解釈する。
("202-11 202-2" の順ではなく "202-2 202-11")

これを実現しようとすると、
・空白区切りで分割して
・"-" の前/後を数値化して
・並べ替え・・・(ソート)
・・・・・ってな処理手順になるかと思います。

せっかく Access を使っているので、ソートの楽な インメモリレコードセットを使って・・・
続きを読んでみようかな ---≫

2011/12/18

Category: 関数を作ってみる

TB: 0  /  CM: 0

top △

1レコードのコピー 


ここにテーブル「TA」があるとします。

フィールドの構成は、
ID : 長整数(主キーで、1 ~ を採番します)
F1 ~ F5 : 型は問いません

ID = 1 のレコードを、ID = 10 として F1 ~ F5 をコピーしたいとします。

どういう処理にすればよいでしょうか
続きを読んでみようかな ---≫

2011/05/22

Category: 関数を作ってみる

TB: 0  /  CM: 0

top △

文字の抜き出し 


旧記事掲載:2010/08/01

"123[567]ABC" という文字列があったとして、"[" "]" で挟まれた
"567" を抜き出したいと思います。

CreateObject("VBScript.RegExp") を用いて、正規表現で・・・・っていう方法もあるようですが、
まずは自分で処理を組んでみて、納得いかないとか、遅いとか、の場合に考えます。

自分で組んでおけば、細かい動きも自在だと思います。

ということで、以下に関数を作っていきたいと思います。


以下では、元の文字列 "123[567]ABC" を変数 sS で表現します。

"567" を切り出す時には、
 InStr(sS, "[") で "[" の位置を、InStr(sS, "]") で "]" の位置を求めておいて、
 それらの位置を使って抜き出していきます。

 iPosS = InStr(sS, "[") ' 値は 4
 iPosE = InStr(sS, "]") ' 値は 8

  Len(sS) は文字数の 11 になっています。

Left / Right を使ってみます。

 まずは、左から "]" 前まで切り取ります。
 Left(sS, iPosE - 1) ' 8 - 1 = 7 結果 "123[567"

 その結果を元に、右から 3 文字分取りたいので
 Right(★, iPosE - (iPosS + 1)) ' 8 - (4+1) = 3

 合わせて記述してみると、
 Right(Left(sS, iPosE - 1), iPosE - (iPosS + 1))


 今度は、右からを考えてみます。
 Right(sS, Len(sS) - iPosS) ' 11 - 4 = 7 結果 "567]ABC"

 その結果を元に、左から 3 文字分取りたいので
 Left(★, iPosE - (iPosS + 1)) ' 8 - (4+1) = 3

 合わせて記述してみると、
 Left(Right(sS, Len(sS) - iPosS), iPosE - (iPosS + 1))

Mid を使ってみます。

 5 文字目から 3 文字分抜き出したいので、
 Mid(sS, iPosS + 1, iPosE - (iPosS + 1))


抜き出したい場合は、Mid を使って、「何文字目から何文字分」が考えやすいでしょうか。

部品がわかったところで、関数として作っていくことにします。

関数を作る際に、同じような処理が必要になるので、こういう指定もできたらいいな・・・・
って、"[" "]" で囲まれた何個目、を指定できるようにしてみます。
(専用/限定した記述よりもチョット処理が増えますが、いろんな場面で使えるかも・・・)

Public Function GetMoji(文字列, 何個目) As String の様なものにします。

 GetMoji("123[567]ABC[012]4", 1) で、"567"
 GetMoji("123[567]ABC[012]4", 2) で、"012"
続きを読んでみようかな ---≫

2011/05/05

Category: 関数を作ってみる

TB: 0  /  CM: 0

top △

文字の切り出し その2 


列A
AAAA-BBB
CCCC-DDD-EE
FFFF-GGG-HH-II

というテーブル「TBL_A」があったとした場合、

列B列C列D列E
AAAABBB  
CCCCDDDEE 
FFFFGGGHHII

のように、"-" で区切ったクエリ表示したい。

っていうものを考えてみたいと思います。
続きを読んでみようかな ---≫

2011/05/05

Category: 関数を作ってみる

TB: 0  /  CM: 0

top △

文字の切り出し 


旧記事掲載:2010/07/31

"123-567ABC" という文字列があったとして、"-" を区切りに
"123" "567ABC" を切り出したいと思います。

以下では、元の文字列 "123-567ABC" を変数 sS で表現します。

"123" を切り出す時には、
 InStr(sS, "-") で "-" の位置を求めておいて、左から何文字目まで・・・・ですね。
 この場合、InStr(sS, "-") は、4 を返すので

 Left(sS, InStr(sS, "-") - 1) ' 左から 3 文字分


"567ABC" を切り出す時には、同様に Len(sS) は文字数の 10 になるので

 Right(sS, Len(sS) - InStr(sS, "-")) ' 右から 6 文字分
とか
 Mid(sS, InStr(sS, "-") + 1) ' 5 文字目以降


視点を変えて、"-" を区切りとして配列データにしてみます。

 Dim sTmp() As String を宣言しておき、
 sTmp = Split(sS,"-")

とすると、sTmp(0) に "123"、sTmp(1) に "567ABC" が格納されます。
sTmp(0) だけを求めたい場合は、 Split(sS,"-")(0) の書き方ができます。

ここで、与えられる文字列の条件を変更してみたいと思います。

変数 sS には、"-" が無い場合があります。あったとしても1つです。
例として、"1234" とか "123-567ABC" とか・・・・

よく質問で見かけますね。

基本的に商品コードは XXXX 1つだけど、色が変わったとかの場合には細番として、
"-" 区切りに、商品コードを XXXX-YYY のようにしている。
XXXX を求めたい。
また、YYY 部分も ###zzz / zzz / zzz### になっていて、 ###(数字)zzz(文字)を求めたい。
XXXX、###、zzzz の桁は、様々・・・
続きを読んでみようかな ---≫

2011/05/05

Category: 関数を作ってみる

TB: 0  /  CM: 0

top △