2013-04-01 234 views
40

我有一个逗号分隔的文件,其中包含许多与下面类似的行。使用String.split()将文本分隔符分割为csv文件

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

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

现在如何尽可能地使用String.split()将逗号分隔符上的上述值分开?

+2

为什么你坚持使用String.split?这个例子有更好的选择吗? – user949300

回答

134
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.] 
+13

+1这是一个非常很酷的正则表达式。我以前没有见过这个,但它的工作原理!我觉得这是非常好的我会奖励你一个赏金:)(注意:赏金过程需要很多天才能完成) – Bohemian

+5

我花了一段时间才弄清楚这个正则表达式在做什么。它会帮助我极大地解释它匹配的逗号后跟偶数个引号(或没有引号)。所以这是有效的,因为逗号的内部引号(即我们不想匹配/分割的引号)应该在它们和行尾之间有奇数的引号。也可能值得注意的是,如果数据可能已经逃脱了引号,我认为这将不起作用。 – glyphx

+1

做这个s.split(',(?=([^ \“] * \”[^ \“] * \”)* [^ \“] * $)',-1)如果你想保留空字符串在结尾。http://stackoverflow.com/questions/13939675/java-string-split-i-want-it-to-include-the-empty-strings-at-the-end – kctang

6

如果字符串所有合式有可能用以下正则表达式:

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

表达确保分裂仅在其后面的偶数(或零)数逗号发生引号(因此不在此类引号内)。

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

+0

阅读CSV文件它工作正常。如果你有这种类型的格式987663,seepzBranch,“Seepz孟买,andheri”,“近红外线,平23号,raghilla商场thane”,seepz, –

9

作为您的问题/要求不那么复杂的自定义方法可以利用,超过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.] 
+0

-1这并不回答这个问题,它特别要求使用'String.split()'的解决方案。顺便说一句,由对java知之甚少的人编写的代码的特征之一是使用'Vector'。 – Bohemian

+4

请解释为什么在这种情况下使用ArrayList而不是Vector(除了由于线程安全性而导致的性能下降)将更加有利。此外,你的礼貌可以使用一些工作,这是一个粗鲁的人的标志之一。 –

+0

我不是粗鲁的;仅仅是事实。这里有一点小技巧......'Vector'不是线程安全的。这是一个破碎的课程,这就是为什么没有人,我真的意味着*没有人*在现实世界中使用它。只有总的初学者使用它,我的猜测是因为讲义十年过时了,特别是因为主张使用Vector的讲师在学术界花费了太多的时间来保持联系,并且老的谚语“如果你不能做它,教它“仍然是真实的。 – Bohemian