2015-12-15 105 views
4

我嘗試用java解析csv,並且遇到以下問題:第二列是一個用雙引號括起來的字符串(它也可能包含逗號),除非字符串本身包含一個雙引號,然後整個字符串用單引號括起來。例如解析csv,不要在單引號或雙引號內拆分

行可能lokk這樣的:

someStuff,"hello", someStuff 
someStuff,"hello, SO", someStuff 
someStuff,'say "hello, world"', someStuff 
someStuff,'say "hello, world', someStuff 

someStuff對於其他元素,也可以包括在同一樣式

引號我正在尋找一種通用的方法,在分割線的佔位符逗號除非用單引號或雙引號括起來才能將第二列作爲字符串。隨着第二專欄中,我的意思是字段:

  • 你好
  • 你好,SO
  • 說: 「你好,世界」
  • 說「你好,世界

我試圖OpenCSV但失敗,因爲人們只能指定一種類型的報價:

public class CSVDemo { 

public static void main(String[] args) throws IOException { 
    CSVDemo demo = new CSVDemo(); 
    demo.process("input.csv"); 
} 

public void process(String fileName) throws IOException { 
    String file = this.getClass().getClassLoader().getResource(fileName) 
      .getFile(); 
    CSVReader reader = new CSVReader(new FileReader(file)); 
    String[] nextLine; 
    while ((nextLine = reader.readNext()) != null) { 
     System.out.println(nextLine[0] + " | " + nextLine[1] + " | " 
       + nextLine[2]); 
    } 
} 

}

與opencsv解決方案失敗的最後一行,其中只有一個雙引號括在單引號:

someStuff | hello | someStuff 
someStuff | hello, SO | someStuff 
someStuff | 'say "hello, world"' | someStuff 
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 1 
+0

你能夠改變的數據? ''說\「你好,世界\」「'應該在opencsv中工作。 –

+0

數據在一個文件中,所以我可以在解析之前更改它,即讀取行,更改/轉義引號然後分割它 –

回答

1

它不會出現opencsv支持這一開箱即用。您可以擴展com.opencsv.CSVParser並實現您自己的算法來處理兩種類型的引號。 This是您將要更改的方法的來源,這裏是一個存根,讓您開始使用。

class MyCSVParser extends CSVParser{ 
    @Override 
    private String[] parseLine(String nextLine, boolean multi) throws IOException{ 
     //Your algorithm here 
    } 
} 
2

如果你真的不能使用真正的CSV解析器,你可以使用正則表達式。這通常不是一個好主意,因爲總是存在邊緣情況,你無法處理,但如果格式嚴格按照你的描述,那麼這可能會起作用。

public void test() { 
    String[] tests = {"numeStuff,\"hello\", someStuff, someStuff", 
     "numeStuff,\"hello, SO\", someStuff, someStuff", 
     "numeStuff,'say \"hello, world\"', someStuff, someStuff" 
    }; 
    /* Matches a field and a potentially empty separator. 
    * 
    * (- Field Group 
    *  \" - Start with a quote 
    *  [^\"]*? - Non-greedy match on anything that is not a quote 
    *  \" - End with a quote 
    * | - Or 
    *  ' - Start with a strop 
    *  [^']*? - Non-greedy match on anything that is not a strop 
    *  ' - End with a strop 
    * | - Or 
    * [^\"'] - Not starting with a quote or strop 
    * [^,$]*? - Non-greedy match on anything that is not a comma or end-of-line 
    * ) - End field group 
    * (- Separator group 
    * [,$] - Comma separator or end of line 
    * ) - End separator group 
    */ 
    Pattern p = Pattern.compile("(\"[^\"]*?\"|'[^\']*?\'|[^\"'][^,\r\n]*?)([,\r\n]|$)"); 
    for (String t : tests) { 
     System.out.println("Matching: " + t); 
     Matcher m = p.matcher(t); 
     while (m.find()) { 
      System.out.println(m.group(1)); 
     } 
    } 
} 
0

它似乎不opencv支持這一點。然而,看看這個前一個問題,我的答案,以及在情況下,其他的答案,他們幫助 您:https://stackoverflow.com/a/15905916/1688441

下面的示例,請不notInsideComma實際上意味着「引號內」。以下代碼可以擴展爲檢查引號和雙引號。

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; 
} 
1

基本上你只需要跟蹤,",'(修整什麼是在中間)。

當您遇到其中一種情況時,請將相應的標誌(例如singleQuoteOpen,doubleQuoteOpen)設置爲true以表示它們已打開並處於忽略逗號模式。

當您遇到適當的結束報價時,請重置標誌並繼續對元素進行切片。

要執行檢查,請停在每個逗號(當不處於忽略逗號模式時)並查看下一個字符(如果有的話,然後修剪)。


注:正則表達式的解決方案是好的,也更短,但對於邊緣情況較少定製(至少沒有大的頭痛)。

0

如果使用單引號和雙引號的是每行一致,人們可以選擇相應的類型,每行報價:

public class CSVDemo { 
    public static void main(String[] args) throws IOException { 
     CSVDemo demo = new CSVDemo(); 
     demo.process("input.csv"); 
    } 

    public void process(String fileName) throws IOException { 
     String file = this.getClass().getClassLoader().getResource(fileName) 
       .getFile(); 

     CSVParser doubleParser = new CSVParser(',', '"'); 
     CSVParser singleParser = new CSVParser(',', '\''); 

     String[] nextLine; 

     try (BufferedReader br = new BufferedReader(new FileReader(file))) { 
      String line; 
      while ((line = br.readLine()) != null) { 
       if (line.contains(",'") && line.contains("',")) { 
        nextLine = singleParser.parseLine(line); 
       } else { 
        nextLine = doubleParser.parseLine(line); 
       } 

       System.out.println(nextLine[0] + " | " + nextLine[1] + " | " 
         + nextLine[2]); 
      } 
     } 
    } 
}