使用 String.split() 拆分带有引号作为文本分隔符的 csv 文件

问题描述 投票:0回答:5

我有一个逗号分隔的文件,其中包含许多类似于下面的行。

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

引号用于转义用于表示多个值的分隔符逗号。

现在,如果可能的话,如何使用

String.split()
在逗号分隔符上拆分上述值?

java csv split
5个回答
211
投票
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.]

25
投票

由于您的问题/要求并不那么复杂,可以使用自定义方法,其执行速度快 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.]

10
投票

如果您的字符串格式正确,则可以使用以下正则表达式:

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

该表达式确保分割仅发生在逗号处,逗号后跟偶数(或零)个引号(因此不在此类引号内)。

尽管如此,使用简单的非正则表达式解析器可能会更容易。


0
投票

最喜欢的答案似乎是正确的,除了尾随逗号的情况。您应该在分割上指定限制参数

public static void main(String[] args) { String s = "Sachin,,M,\"Maths,Science,English\",Need to improve in these subjects.,,,"; String[] splitted = s.split(",(?=([^\"]*\"[^\"]*\")*[^\"]*$)", -1); System.out.println(Arrays.toString(splitted)); }
否则结果将不包括最后三列。


-1
投票
在处理 csv 字符串时,我们需要了解以下几点。

    行中的每个元组都将以“(引号)开头或不以”(引号)开头。 a) 如果它以“(引号)开头,那么它必须是特定列的值。 b) 如果是直接启动则必须是 header。 例如:'标题1,标题2,标题3,“值1”,“值2”,“值3”'; 这里 Header1,Header2,Header3 是列名,剩下的是值。
在进行分割时我们需要记住的要点是您需要检查吐痰是否正确完成。 a) 获取分割值并检查 value 中的引号数量(数量必须为偶数) b) 如果计数为奇数,则附加下一个分割值。 c) 重复过程 a,b 直到引号相等。

© www.soinside.com 2019 - 2024. All rights reserved.