2013-04-01 232 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