2009-09-17 52 views
15

我知道了,現在我有兩個問題。但我很開心!用java中的RegEx解析CSV輸入

我從this advice開始不嘗試分割,而是匹配什麼是可接受的字段,並從那裏擴展到這個表達式。

final Pattern pattern = Pattern.compile("\"([^\"]*)\"|(?<=,|^)([^,]*)(?=,|$)"); 

表達看起來像這樣沒有惱人的轉義引號:

"([^"]*)"|(?<=,|^)([^,]*)(?=,|$) 

這是工作很適合我 - 無論它符合「兩個報價,無論是他們之間的」或「之間的東西該行的開頭或逗號以及該行的末尾或逗號「。迭代通過比賽可以讓我看到所有的場地,即使它們是空的。例如,

the quick, "brown, fox jumps", over, "the",,"lazy dog" 

分解成

the quick 
"brown, fox jumps" 
over 
"the" 

"lazy dog" 

太好了!現在我想放棄引號,所以我添加了前面和後面的非捕獲組,就像我爲逗號所做的那樣。

final Pattern pattern = Pattern.compile("(?<=\")([^\"]*)(?=\")|(?<=,|^)([^,]*)(?=,|$)"); 

再次表達的是:

(?<=")([^"]*)(?=")|(?<=,|^)([^,]*)(?=,|$) 

而是期望的結果

the quick 
brown, fox jumps 
over 
the 

lazy dog 

現在我得到這樣的故障:

the quick 
"brown 
fox jumps" 
,over, 
"the" 
,, 
"lazy dog" 

我缺少什麼?

+0

我假設你的文本本身不能包含引號? – 2009-09-18 10:28:53

+2

謝天謝地沒有。那時我只會使用openCSV庫。 – 2009-10-12 18:11:32

+0

其他用於Java的CSV庫:http://stackoverflow.com/questions/101100/csv-api-for-java – Thilo 2013-08-02 12:42:30

回答

8

運算符優先級。基本上沒有。這一切都是從左到右。所以,或(|)正在申請關閉的引號先行和逗號前瞻

嘗試:

(?:(?<=")([^"]*)(?="))|(?<=,|^)([^,]*)(?=,|$) 
+0

啊,我明白了。所以我應該試着將報價組合在一起,也是逗號的東西。不幸的是,在(?:)中引用引用內容似乎沒有任何作用。我嘗試將它添加到逗號的東西中,也將它們分組在另一組括號中,但都沒有任何效果。我將繼續尋找正確的語法;如果我在別人發佈之前發現它,我會給你答案。 – 2009-09-17 23:13:38

4

當我開始明白我做了錯事,我也開始明白如何錯綜複雜lookarounds正在做這個。我終於意識到,我不想要所有匹配的文本,我想要特定的組。我最終使用了與我的原始正則表達式非常相似的東西,只是我沒有對縮略的逗號做一個前瞻,我認爲它應該更有效一些。這是我的最終代碼。

package regex.parser; 

import java.util.ArrayList; 
import java.util.regex.Matcher; 
import java.util.regex.Pattern; 

public class CSVParser { 

    /* 
    * This Pattern will match on either quoted text or text between commas, including 
    * whitespace, and accounting for beginning and end of line. 
    */ 
    private final Pattern csvPattern = Pattern.compile("\"([^\"]*)\"|(?<=,|^)([^,]*)(?:,|$)"); 
    private ArrayList<String> allMatches = null;  
    private Matcher matcher = null; 
    private String match = null; 
    private int size; 

    public CSVParser() {   
     allMatches = new ArrayList<String>(); 
     matcher = null; 
     match = null; 
    } 

    public String[] parse(String csvLine) { 
     matcher = csvPattern.matcher(csvLine); 
     allMatches.clear(); 
     String match; 
     while (matcher.find()) { 
      match = matcher.group(1); 
      if (match!=null) { 
       allMatches.add(match); 
      } 
      else { 
       allMatches.add(matcher.group(2)); 
      } 
     } 

     size = allMatches.size();  
     if (size > 0) { 
      return allMatches.toArray(new String[size]); 
     } 
     else { 
      return new String[0]; 
     }   
    } 

    public static void main(String[] args) {   
     String lineinput = "the quick,\"brown, fox jumps\",over,\"the\",,\"lazy dog\""; 

     CSVParser myCSV = new CSVParser(); 
     System.out.println("Testing CSVParser with: \n " + lineinput); 
     for (String s : myCSV.parse(lineinput)) { 
      System.out.println(s); 
     } 
    } 

} 
+0

我覺得我應該重新說明這僅僅是爲了我的娛樂,並不保證能夠正常工作,而且如果您嘗試在其中一個字段中包含轉義的分隔符,肯定無法工作。在sourceforge上使用開源java csv庫,或者在需要「真實」的地方使用。 – 2009-11-19 06:08:59

1

我知道這是不是OP想要的東西,但對於其他讀者的方法與string.replace一個可以用來移除每一元素引號的有機磷農藥當前正則表達式的結果陣列英寸

+0

也是如此。 – 2009-09-18 01:37:28

5
(?:^|,)\s*(?:(?:(?=")"([^"].*?)")|(?:(?!")(.*?)))(?=,|$) 

這應該做你想做的。

說明:

(?:^|,)\s* 

的模式應該有一個開始,或字符串的開頭。另外,在開始時忽略所有空格。

前瞻,看看是否有其他報價

(?:(?=")"([^"].*?)") 

開始。如果是,則匹配非貪婪到明年的報價。

(?:(?!")(.*?)) 

如果它不是以引號開頭,那麼非貪婪地匹配,直到下一個逗號或字符串結束。

(?=,|$) 

該模式應以逗號或字符串結尾結尾。

+0

此解決方案適用於我而不是選定的答案,謝謝! – 2017-02-16 07:18:06

+0

如果字符串以雙引號開始?例如: 」」」,」,,,,」」」」。 (沒有點) – slodeveloper 2017-12-01 23:37:31