#改行含んだCSVをパースしてString()に収めるやつ
改行ありのCSVとか勘弁してほしい所ではあるが、やってくるものは受け止めなければならないので
ネットで誰か作ってないかなーとか思ったがしっくりくるのが無かったので嫌々作ったやつのメモである
※textfieldparserで対応出来るのを知らずに書いてました。そっち使ったほうが早いので皆さんはそちらを使われるといいと思います。
###ざっくり使い方
VB.NET
Using csv = New CSVFile("ここに読込むファイルパス")
Dim data As String()
While Not csv.ReadToEnd
data = csv.ReadLineData()
'改行は配列におさまっていい感じになってるはず
End While
End Using
###作ったクラス
VB.NET
Imports System.IO
Imports System.Text
Imports System.Text.RegularExpressions
''' <summary>
''' CSVファイルを扱う為のクラス
''' </summary>
''' <remarks>ダブルクォートのみ対応</remarks>
Public Class CSVFile
Implements IDisposable
Private sr As StreamReader
Private fs As FileStream
Private pos As Long
Private Const HASEND_PATTERN = "^.*([^""]""|"",""""|,[^""]*)$"
Private _ReadToEnd As Boolean = False
Public ReadOnly Property ReadToEnd As Boolean
Get
Return _ReadToEnd
End Get
End Property
''' <summary>
''' CSVファイルオブジェクトを作成し、ファイルをオープンする。
''' </summary>
''' <param name="filepath"></param>
''' <param name="encodeing"></param>
''' <remarks></remarks>
Sub New(ByVal filepath As String, Optional ByVal encodeing As String = "Shift_JIS")
'文字コード指定
Dim enc As Encoding = Encoding.GetEncoding(encodeing)
'ファイルストリームを開く
Me.fs = File.OpenRead(filepath)
Me.pos = Me.fs.Position
Me.sr = New StreamReader(fs, enc)
End Sub
''' <summary>
''' CSVデータとして改行等を考慮し、1行のデータとして返却します。
''' </summary>
''' <returns></returns>
''' <remarks></remarks>
Public Function ReadLine(Optional simple As Boolean = False) As String
'ファイルの任意の場所にシーク
'fs.Seek(pos, SeekOrigin.Begin)
'行データ読み込み
Dim line = sr.ReadLine()
If simple Then
Return line
End If
'ファイルの終端なら何も返さない
If line Is Nothing Then
_ReadToEnd = True
Return Nothing
End If
'行末があるバターンならそのまま返却
If Regex.IsMatch(line, HASEND_PATTERN) Then
Return line
End If
'行末が出るまで文字列を連結して返却
Dim csvLine = New StringBuilder(line)
While True
line = sr.ReadLine()
If line Is Nothing Then
Return Nothing
End If
csvLine.Append(vbCrLf).Append(line)
If Regex.IsMatch(line, HASEND_PATTERN) Then
Exit While
End If
End While
'改行を含むデータを返却
Return csvLine.ToString()
End Function
''' <summary>
''' 行データをデータ配列で返却
''' </summary>
''' <returns></returns>
Public Function ReadLineData(Optional simple As Boolean = False) As String()
Return CSVFile.SplitData(ReadLine(simple))
End Function
''' <summary>
''' CSV行データをデータ毎に分割します。
''' </summary>
''' <param name="csvline"></param>
''' <returns></returns>
''' <remarks>考慮が甘い為、イレギュラーパターンは別途対応</remarks>
Public Shared Function SplitData(ByVal csvline As String) As String()
Dim ret As New List(Of String)
Dim tmp As String() = {}
Dim tval As String = ""
If csvLine Is Nothing Then
Return {}
End If
'とりあえずカンマで分解
tmp = csvline.Split(",")
Dim nextflg As Boolean = False
For Each val As String In tmp
If nextflg Then
tval += val
nextflg = False
Else
tval = val
End If
'OKかNGか判定
If Regex.IsMatch(tval, "^(""[^""|""""]*""|[^""]*)$") Then
' マッチしていればそのままで終了
' ^([^"]*)$ -> \1
If Regex.IsMatch(tval, "^([^""]*)$") Then
ret.Add(tval)
Continue For
End If
' マッチしていれば抽出して終了
' ^"([^"]*)"$ -> \1
Dim match As Match = Regex.Match(tval, "^""([^""]*)""$")
If match.Success Then
ret.Add(match.Value)
Continue For
End If
' マッチしていれば抽出して
match = Regex.Match(tval, "^"".*([^""]+|"""")""$")
If match.Success Then
' 両サイドのだぶくるくぉーとを外す
match = Regex.Match(tval, "^""(.*)""$")
If match.Success Then
' ダブルクォートのエスケープ解除で終了
ret.Add(match.Value.Replace("""""", """"))
Continue For
End If
End If
End If
'NG(ダブルくぉーとありでエンドなし
' 移行の要素を次の正規表現にマッチするまでカンマ区切りで連結
If Regex.IsMatch(tval, "^"".*([^""]+|"""")""$") Then
' 両サイドのだぶくるくぉーとを外す
Dim match = Regex.Match(tval, "^""(.*)""$")
If match.Success Then
' ダブルクォートのエスケープ解除で終了
ret.Add(match.Value.Replace("""""", """"))
Continue For
End If
End If
nextflg = True
Next
Return ret.ToArray()
End Function
#Region "IDisposable Support"
Private disposedValue As Boolean ' 重複する呼び出しを検出するには
' IDisposable
Protected Overridable Sub Dispose(disposing As Boolean)
If Not Me.disposedValue Then
If disposing Then
If Not fs Is Nothing Then
fs.Dispose()
End If
If Not sr Is Nothing Then
sr.Dispose()
End If
End If
fs = Nothing
sr = Nothing
End If
Me.disposedValue = True
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
#End Region
End Class
世の中から改行付CSVだとかダブルクォートやカンマを多用するエンドユーザが居なくなる事をここに願う。