前回に続いて CSV の読み込み方法を紹介します。
まず、利用する CSV のサンプルですが、郵便局の Web サイトからダウンロードできる 郵便番号(ローマ字) を利用します。フォーマットは 1 郵便番号当たり 7 項目の CSV ファイルとなっています。
|
"0600000","北海道","札幌市 中央区","以下に掲載がない場合","HOKKAIDO","SAPPORO SHI CHUO KU","IKANIKEISAIGANAIBAAI" "0640941","北海道","札幌市 中央区","旭ケ丘","HOKKAIDO","SAPPORO SHI CHUO KU","ASAHIGAOKA" ・・・ |
CSV ファイルなどのテキストファイルの読み込みには Input # と Line Input # の 2 つの方法があるのですが、今回は Input # を紹介します。
Input #
このステートメントの構文は次の通りです。
| Input #fileNumber , variableList |
| fileNumber | データを読み込むファイル番号 |
| variableList | 読み込んだデータをセットする変数リスト(カンマ区切り) |
変数リストの設定は LotusScript のプログラミングであまり登場しないパターンで、データを受け取る変数名を必要な数だけカンマ区切りで列挙します。例えば、事例の CSV の場合では、以下のように記述します。青字部分が変数リストとなります。
| Dim iFP As Integer Dim sZip As String Dim sKj1 As String Dim sKj2 As String Dim sKj3 As String Dim sEn1 As String Dim sEn2 As String Dim sEn3 As String 'ファイルオープン(読み込みモード) iFP = FreeFile() Open "c:\tmp\KEN_ALL_ROME.CSV" For Input As #iFP Input #iFP, sZip, sKj1, sKj2, sKj3, sEn1, sEn2, sEn3 ・・・ |
実行すると下図のように CSV 内の各カラムの値がそれぞれの変数に代入されます。
カンマをデータの区切りとして分離、文字列の始めと終わりのダブルクォーテーションを削除してくれることが特徴です。
この挙動からわかる通り、Input # は CSV ファイルの読み込みを意識した仕様になっていることがわかります。
サンプルプログラム
では、具体的に事例の CSV ファイルをフォームに読み込むエージェントを紹介します。
|
Option Declare Sub Initialize Dim ns As New NotesSession Dim ndb As NotesDatabase Dim nd As NotesDocument Dim iFP As Integer Dim sZip As String Dim sKj1 As String Dim sKj2 As String Dim sKj3 As String Dim sEn1 As String Dim sEn2 As String Dim sEn3 As String '初期化 Set ndb = ns.CurrentDatabase 'ファイルオープン iFP = FreeFile() Open "c:\tmp\KEN_ALL_ROME.CSV" For Input As #iFP '1件目取得 Input #iFP, sZip, sKj1, sKj2, sKj3, sEn1, sEn2, sEn3 Do Until EOF(iFP) '読み込んだデータを文書に保存 Set nd = ndb.CreateDocument() nd.Form = "fZip_Rome" nd.ZipCode = sZip nd.Address1_Kj = sKj1 nd.Address2_Kj = sKj2 nd.Address3_Kj = sKj3 nd.Address1_En = sEn1 nd.Address2_En = sEn2 nd.Address3_En = sEn3 Call nd.Save(True, True) '次のデータを取得 Input #iFP, sZip, sKj1, sKj2, sKj3, sEn1, sEn2, sEn3 Loop Close End Sub |
Do ~ Loop の判定で使用している EOF(iFP) はそのファイルが最後(End Of File)であるかを判定する命令です。ループの最後の Input # で次のデータを読み込んでループを繰り返しています。これでファイルを順に最後まで読み込むこととなります。
Input # の注意点
上記の通り Input # は CSV 読み込みの処理ではとても便利に利用できます。ただ、おいしい話には裏があるもので、注意点がいくつかあります。
◇ 数値変換できない場合は 0 となる
例にはありませんが、数値変数を指定すると数値として読み込んでくれる機能があります。うまく使えば、データの型操作を最小限にすることができるのですが、利用上の注意があります。それは、読み込んだデータが数値に変換できない場合は、0 となることです。
例えば、郵便番号 sZip を数値(Integer 型)に変更して実行します。
| Dim sZip As Integer |
変数が数値型であるため、ファイルから変数に割り当てられるデータは、ダブルクォーテーションが付いた "0640941" のような値となります。ダブルクォーテーションは数値に変換できないので変数の値は 0 となり、結果作成される文書の値も 0 となってしまいます。
◇ 特殊文字に注意
CSV ファイルのフォーマットでは、ダブルクォーテーションで括られた範囲内が文字列となります。ただ、文字列内にダブルクォーテーションを含める場合には、"" のように二重に書くことになっています(ダブルクォーテーションエスケープ)。ところが、Input # では対応していないようです。
少々意地悪なテストデータを与えてみました。Input # 経由で読み取れたデータに色を付けると次のようになりました。『以下に"掲載"がない場合』と読み取ってほしいところが、3 データに分離されてしまいました。どうやら、文字列内のダブルクォーテーションは区切り文字として判定するようです。
| "0600000","北海道","札幌市 中央区","以下に""掲載""がない場合","HOKKAIDO","SAPPORO SHI CHUO KU","IKANI,KEISAI,GANAIBAAI" |
ちなみに、最後のカラムにあるように、文字列内の ,(カンマ)は区切り文字ではなく、データとして正しく取り扱いました。文字列内のカンマは区切り文字と判定しないようです。
特殊文字を含む CSV の場合は対応が完全ではないので、注意がいるようですね。
◇ レコードという考え方がない
Input # は区切り文字に従い順にデータを読み込むことに特化しています。例えば以下のように読み込み変数を一つだけ指定して実行してみます。
| Input #iFP, sZip |
すると郵便番号を読み込んだ後、次は同じ1行目の都道府県名が読み込まれました。行単位で読み込みを行う場合には、行内に存在するすべてのカラム数分の変数を記述する必要がある点に注意が必要です。
もし、一部のカラムしか処理に必要ない場合には、ダミーの変数をセットすることができます。例えば最初のカラム以外不要なのであれば、次のように記述できます。
| Input #iFP, sZip, sTmp, sTmp, sTmp, sTmp, sTmp, sTmp |
無用な変数宣言を減らせるので、少しだけコードが短く、見やすくできますね。
まとめ
今回は CSV 取り込みに特化した Input # を紹介しました。便利な機能ではあるのですが、注意点がいくつか存在しました。
特に、カラムがずれる現象が発生には要注意です。ずれが発生すると後続のデータでは、数値カラムに文字が入ったりします。通常 LotusScript では型変換エラーが発生して気付けるのですが、上記の通り Input # ではエラーが発生しません。レコード単位で処理する機能がないことと相まって、いったんずれが発生すると、元に戻ることがありません。
絶望的な結果となったにも関わらず、何となく動いてしまい、正常終了扱いとなっていることがあります...。



0 件のコメント:
コメントを投稿