簡體   English   中英

在java中使用RegEx解析CSV輸入

[英]Parsing CSV input with a RegEx in java

我知道,現在我有兩個問題。 但我很開心!

我從這個建議開始不嘗試拆分,而是匹配什么是可接受的字段,並從那里擴展到這個表達式。

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"

我錯過了什么?

運算符優先級。 基本上沒有。 這一切都是從左到右。 所以or(|)適用於結束引用前瞻和逗號前瞻

嘗試:

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

這應該做你想要的。

說明:

(?:^|,)\s*

模式應該以字符串或字符串的開頭開頭。 另外,忽略開頭的所有空格。

Lookahead並查看其余部分是否以引號開頭

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

如果確實如此,則非貪婪地匹配到下一個引用。

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

如果它不以引號開頭,則匹配非貪婪直到下一個逗號或字符串結尾。

(?=,|$)

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

當我開始理解我做錯了什么時,我也開始明白這些看起來有多么復雜。 我終於意識到我不想要所有匹配的文本,我想要它內部的特定組。 我最終使用的東西與我原來的RegEx非常相似,只是我沒有對結束逗號做一個預測,我認為這應該更有效率。 這是我的最終代碼。

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

}

我知道這不是OP想要的,但對於其他讀者,可以使用String.replace方法之一來去除OPs當前正則表達式的結果數組中每個元素的引號。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM