CSV形式の文字列を文字列型配列に分割する

注意:
この文書は以前「.NETでいきまっしょい!」で公開していたものですが、公開以降メンテナンスされていません。 今や古い情報となった内容が記載されている場合があるのでご注意ください。

 StreamReaderクラスなどには、CSVファイルを読み込むようなメソッドは存在しない。 CSVファイルを読み込み、データを取得する場合は、独自に読み込みのプログラムを書く必要がある。
 次のコードでは、CSVファイルから読み込まれたと仮定した文字列について、カンマで分割したものを文字列の配列として返している。 ダブルクォーテーションでくくられたデータや空データは考慮されているが、改行文字がデータとして含まれている場合は想定していない。
VB.NET
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
Sub Main()

    Dim line As String = ",test,"""",123,""Hello, world"",,,sample,"
    Dim splitted As String()

    Console.WriteLine("[元の文字列]")
    Console.WriteLine(line)

    splitted = SplitCSVString(line)

    Console.WriteLine("[分割された文字列]")

    Dim str As String

    For Each str In splitted

        Console.WriteLine(str)

    Next

End Sub

' CSVを文字列の配列に分割する
' ダブルクォーテーションでくくられた部分も正しく認識する
Function SplitCSVString(ByVal str As String) As String()

    If str Is Nothing Then Throw New ArgumentNullException("str")

    Dim pos As Integer        ' 現在の文字の位置
    Dim len As Integer        ' 文字列の長さ
    Dim last As Integer       ' 最後に見つかったカンマの次の位置
    Dim ch As Char            ' 現在の文字
    Dim quot As Boolean       ' ダブルクォーテーションでくくられた部分にいるか否か
    Dim splitted As ArrayList ' 分割された文字列

    pos = 0
    len = str.Length
    last = 0
    ch = Char.MinValue
    quot = False
    splitted = New ArrayList()

    While (pos < len)

        ch = str.Chars(pos)

        If Not quot AndAlso ch = ","c Then

            ' ダブルクォーテーションでくくられた部分ではないところでカンマが見つかった場合
            Dim val As String = str.Substring(last, pos - last)

            ' ダブルクォーテーションでくくられている場合、クォーテーションを取り除く
            If val.StartsWith("""") AndAlso val.EndsWith("""") Then

                val = val.Substring(1, val.Length - 2)

            End If

            ' 値をリストに追加
            splitted.Add(val)

            ' 位置を保存
            last = pos + 1

        ElseIf ch = """"c Then

            ' ダブルクォーテーションの状態
            quot = Not quot

        End If

        ' 次の文字
        pos += 1

    End While

    ' 最後がカンマで終わっている場合、空文字を追加
    If ch = ","c Then splitted.Add("")

    ' 文字列型配列として値を返す
    Return DirectCast(splitted.ToArray(GetType(String)), String())

End Function
C#
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
static void Main(string[] args)
{
    string line = ",test,\"\",123,\"Hello, world\",,,sample,";
    string [] splitted;

    Console.WriteLine( "[元の文字列]" );
    Console.WriteLine( line );

    splitted = SplitCSVString( line );

    Console.WriteLine( "[分割された文字列]" );

    foreach ( string str in splitted )
    {
        Console.WriteLine( str );
    }
}

// CSVを文字列の配列に分割する
// ダブルクォーテーションでくくられた部分も正しく認識する
static string[] SplitCSVString( string str )
{
    if ( str == null ) throw new ArgumentNullException( "str" );

    int  pos;           // 現在の文字の位置
    int  len;           // 文字列の長さ
    int  last;          // 最後に見つかったカンマの次の位置
    char ch;            // 現在の文字
    bool quot;          // ダブルクォーテーションでくくられた部分にいるか否か
    ArrayList splitted; // 分割された文字列

    pos = 0;
    len = str.Length;
    last = 0;
    ch = Char.MinValue;
    quot = false;
    splitted = new ArrayList();

    while ( pos < len )
    {
        ch = str[pos];

        if ( !quot && ch == ',' ) 
        {
            // ダブルクォーテーションでくくられた部分ではないところでカンマが見つかった場合
            string val = str.Substring( last, pos - last );

            // ダブルクォーテーションでくくられている場合、クォーテーションを取り除く
            if ( val.StartsWith( "\"" ) && val.EndsWith( "\"" ) ) 
            {
                val = val.Substring( 1, val.Length - 2 );
            }

            // 値をリストに追加
            splitted.Add( val );

            // 位置を保存
            last = pos + 1;
        }
        else if ( ch == '"' ) 
        {
            // ダブルクォーテーションの状態
            quot = !quot;
        }

        // 次の文字
        pos += 1;
    }

    // 最後がカンマで終わっている場合、空文字を追加
    if ( ch == ',' ) splitted.Add( "" );

    // 文字列型配列として値を返す
    return (string[])splitted.ToArray( typeof( string ) );
}
出力結果
[元の文字列]
,test,"",123,"Hello, world",,,sample,
[分割された文字列]

test

123
Hello, world


sample

Press any key to continue

 このメソッドは、CSVファイルから読み込まれた各行を一行ずつ文字列型配列に分割するような作業で使用されることを想定している。