web-dev-qa-db-ja.com

String.split()を使用して、テキスト区切り文字として引用符でCSVファイルを分割する

以下のような多くの行を持つコンマ区切りファイルがあります。

_Sachin,,M,"Maths,Science,English",Need to improve in these subjects.
_

引用符は、複数の値を表すために使用される区切り記号コンマをエスケープするために使用されます。

では、可能であれば、String.split()を使用して上記の値をコンマ区切り文字で分割するにはどうすればよいですか?

47
FarSh018
public static void main(String[] args) {
    String s = "Sachin,,M,\"Maths,Science,English\",Need to improve in these subjects.";
    String[] splitted = s.split(",(?=([^\"]*\"[^\"]*\")*[^\"]*$)");
    System.out.println(Arrays.toString(splitted));
}

出力:

[Sachin, , M, "Maths,Science,English", Need to improve in these subjects.]
167
Achintya Jha

あなたの問題/要件はそれほど複雑ではないため、20倍以上高速に実行し、同じ結果を生成するカスタムメソッドを利用できます。これは、解析されるデータサイズと行数に基づいて可変であり、正規表現を使用するより複雑な問題には必須です。

import Java.util.Arrays;
import Java.util.ArrayList;
public class SplitTest {

public static void main(String[] args) {

    String s = "Sachin,,M,\"Maths,Science,English\",Need to improve in these subjects.";
    String[] splitted = null;

 //Measure Regular Expression
    long startTime = System.nanoTime();
    for(int i=0; i<10; i++)
    splitted = s.split(",(?=([^\"]*\"[^\"]*\")*[^\"]*$)");
    long endTime =   System.nanoTime();

    System.out.println("Took: " + (endTime-startTime));
    System.out.println(Arrays.toString(splitted));
    System.out.println("");


    ArrayList<String> sw = null;        
 //Measure Custom Method
            startTime = System.nanoTime();
    for(int i=0; i<10; i++)
    sw = customSplitSpecific(s);
    endTime =   System.nanoTime();

    System.out.println("Took: " + (endTime-startTime));
    System.out.println(sw);         
}

public static ArrayList<String> customSplitSpecific(String s)
{
    ArrayList<String> words = new ArrayList<String>();
    boolean notInsideComma = true;
    int start =0, end=0;
    for(int i=0; i<s.length()-1; i++)
    {
        if(s.charAt(i)==',' && notInsideComma)
        {
            words.add(s.substring(start,i));
            start = i+1;                
        }   
        else if(s.charAt(i)=='"')
        notInsideComma=!notInsideComma;
    }
    words.add(s.substring(start));
    return words;
}   

}

私のコンピューターでは、これにより以下が生成されます。

Took: 6651100
[Sachin, , M, "Maths,Science,English", Need to improve in these subjects.]

Took: 224179
[Sachin, , M, "Maths,Science,English", Need to improve in these subjects.]
16

文字列がすべて整形式の場合、次の正規表現を使用して可能です。

String[] res = str.split(",(?=([^\"]|\"[^\"]*\")*$)");

この式は、偶数(またはゼロ)の引用符が続くコンマでのみ分割が行われるようにします(したがって、そのような引用符内ではありません)。

それでも、単純な非正規表現パーサーを使用する方が簡単な場合があります。

6
Howard