みなさん、こんにちは!
タカハシ(@ntakahashi0505)です。
エクセルVBAでCSVファイルを取り込む方法シリーズです。
前回、Splitを使ってCSVからのデータをワークシートに転記をする方法についてお伝えしました。
ただし、残念ながらこのプログラムではうまく取り込めない例がいくつか存在しています。
今回はそのうちの一つ、CSVをワークシートに取り込んだときに改行されずに一行になってしまうパターンについてどう回避するかについてお伝えしたいと思います。
ではよろしくお願いします!
前回のおさらい:CSVファイルを一行ずつ取得してカンマでスプリットする
まず前回のおさらいですが、プログラムはコチラでしす。
Sub getCSV() Dim ws As Worksheet Set ws = ThisWorkbook.Worksheets(1) Dim strPath As String strPath = "C:\Users\Noriaki\Dropbox\40_ブログ\vba-csv\test\ラーメン店アンケート.csv" Dim i As Long, j As Long Dim strLine As String Dim arrLine As Variant 'カンマでsplitして格納 Open strPath For Input As #1 'csvファイルをオープン i = 1 Do Until EOF(1) Line Input #1, strLine arrLine = Split(strLine, ",") 'strLineをカンマで区切りarrLineに格納 For j = 0 To UBound(arrLine) ws.Cells(i, j + 1).Value = arrLine(j) Next j i = i + 1 Loop Close #1 End Sub
おおまかな流れとしては
- OpenでCSVファイルをオープン
- CSVファイルが終了するまで
- CSVファイルから1行取得
- 取得した文字列をカンマでSplit
- Splitした要素をセルに転記
- CloseでCSVファイルをクローズ
という流れになります。
このプログラムでうまく取り込めないCSVのパターンはどういったものでしょうか。
CSVを取り込んでも改行がうまくされないパターン
とあるCSVを上記プログラムで取り込んでみると…
うまく取り込めません。
本来、一行ずつ改行してほしいところなのですが、改行されずにすべての値が1行目に転記されてしまいました。
このように改行がうまくできないパターンが存在します。
CSVファイルに問題があるのか、エディタで確認をしてみます。
うーん…とくに問題があるようには見えませんね。
再度先ほどのエクセルの出力結果をよく見てみますと
I1セルに注目して頂くと二つの値が1つのセルに格納されていました。いわゆるショートカットキーで Alt + Enter
とするセル内改行ですね。
この辺りに解決のヒントがありそうです。
3種類の改行コード
世の中で取り扱われている「改行」にはいくつかの種類があることをご存知でしたか?
調べてみますと
改行コードとは、テキストファイル中で改行を意味する文字コードのこと。正確には、改行してカーソルを行頭に復帰する動作を指示するコードのこと。
文字コード体系の種類には依存しないが、もともと「CR」(Carriage Return : 行頭復帰)と「LF」(Line Feed : 改行)の2つのコードが存在していたことから、WindowsではCR+LF、Mac OSではCR、UNIXではLFが使われている。IT用語辞典:改行コード
とこのように、プラットフォームでメインで使う改行コードが異なるということなんですね。
CSVはプラットフォーム間でデータをやりとりすることも多いわけで、別のプラットフォームで作成したCSVはこの「改行コードの違い」が発生している場合があるということですね。
改行がされなかった理由
たね明かしをしますと、今回使用したCSVの一行の終わりを表す改行コードにはLFコードが使われていたんですね。
Line InputではCRコードが出現するまでを一行として判別しますので、LFコードがあっても一行の終わりとは判定されません。
ではLFコードは無視されているのか?ということなのですが、そうではありません。
勘のいい方はお気づきだと思いますが、一方でLFコードはセル内改行として処理 をされていたんですね。
これにて理由はわかりましたので、プログラムを修正していきます。
CSVファイルのLFコードを判定してSplitするプログラム
修正したプログラムはこちらです。
'CSVファイルの取り込み LFコードでスプリット→カンマでスプリットするパターン Sub getCSV2() Dim ws As Worksheet Set ws = ThisWorkbook.Worksheets(1) Dim strPath As String strPath = "C:\Users\Noriaki\Dropbox\40_ブログ\vba-csv\test\ラーメン店アンケート_vbLf.csv" Dim i As Long, j As Long Dim strLine As String Dim tmp As Variant 'LFコードでsplitして格納 Dim arrLine As Variant 'カンマでsplitして格納 Open strPath For Input As #1 'csvファイルをオープン Line Input #1, strLine 'CRコードがないので1行取り込めばCSVファイル全てを取り込める Close #1 tmp = Split(strLine, vbLf) 'strLineをLFコードで区切りtmpに格納 For i = 0 To UBound(tmp) arrLine = Split(tmp(i), ",") 'tmp(i)をカンマで区切りarrLineに格納 For j = 0 To UBound(arrLine) ws.Cells(i + 1, j + 1).Value = arrLine(j) Next j Next i End Sub
今回のプログラムのメインの流れは
- Line InputでCSVファイルを文字列strLineに取り込む
- strLineをLFコードで分割して、分割した要素を配列tmpに格納
- 配列tmpに格納されている要素一つ一つに対してカンマで分割して、分割した要素を配列arrLineに格納
- 配列arrLineに格納されている要素をセルに書き込む
という流れです。
つまり、まず改行コードLFで分割してから、さらにそれをカンマで分割するという方針です。
以降でいくつかポイントを解説します。
LFコードのCSVは1行取り込めば全てを取り込める
まず15行~17行です。
Open strPath For Input As #1 'csvファイルをオープン Line Input #1, strLine 'CRコードがないので1行取り込めばCSVファイル全てを取り込める Close #1
前回のプログラムでは、CSVの取り込みにファイルの終わりまでを繰り返すDo Until EOF(1)~Loopを使用していましたが、今回は使用していません。
Line Inputを1回だけして、さっさとCSVファイルをCloseしてしまっています。
なぜこれで良いのでしょうか?
繰り返しになりますが、Line Input はCRコードを1行の終わりと判定します。
今回対象とするCSVファイルはCRコードが存在していないので、Line Inputはファイルの終わりまで「行の終わり」を判定することはありません。
したがって、1回Line Inputをしてしまえば、CSVファイル全体を1行として取り込めるということです。
改行コードのVBA定数
次に19行目です。
tmp = Split(strLine, vbLf) 'strLineをLFコードで区切りtmpに格納
ここが今回のキモですね。
LFコードでSplitをするのですが、「vbLf」という見慣れないものありますね。
改行コードなどを指定するときには定数というものを使います。
定数というのは、特定の値に名前をつけたものをいいます。変数に似ていますが、一度格納した値を変更することはできません。
VBAには改行コードについて定義済みの定数が用意されています。
VBA定数 | プラットフォーム | 名称・説明 |
---|---|---|
vbCr | Mac OS | CRコード。キャリッジリターン |
vbLf | UNIX | LFコード。ラインフィード |
vbCrLf | Windows | CRコードとLFコードの組み合わせ |
vbNewLine | ― | プラットフォームで適切な改行コードを使用 |
このように4種類の定数を利用することができます。
今回はLFコードを利用したいので、定数vbLfを使っているというわけです。
まとめ
以上、改行がうまくされないパターンのCSV、つまりLFコードを使用したCSVファイルをエクセルVBAで取り込む方法についてお伝えしました。
配列が複数出てくるので若干ややこしいかも知れませんが、CSVの取り込み処理は一度作成するといろんなプログラムで使い回しが利くので、ぜひマスター頂ければと思います。
次回ですが、これ以外にもCSVがうまく取り込めないパターンがいくつかありますので、それを一つ一つやっつけていきたいと思います。
どうぞお楽しみに!