[英]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.