質問
今、2つの問題があります。しかし、私は楽しんでいます!
このアドバイスは分割しようとせず、代わりに許容可能なフィールドに一致するように、そこからこの式に展開します。
final Pattern pattern = Pattern.compile("\"([^\"]*)\"|(?<=,|^)([^,]*)(?=,|$)");
迷惑なエスケープされた引用符のない式は次のようになります。
"([^"]*)"|(?<=,|^)([^,]*)(?=,|$)
これは私にとってはうまく機能しています-「2つの引用符とその間にあるもの」に一致するか、「行の先頭またはカンマと行の終わりまたはカンマの間にあるもの」に一致します。マッチを繰り返し処理すると、空のフィールドでもすべてのフィールドが取得されます。たとえば、
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で、残りが引用符で始まるかどうかを確認します
(?:(?=")"([^"].*?)")
一致する場合、次の引用まで貪欲ではない一致。
(?:(?!")(.*?))
引用符で始まらない場合は、次のコンマまたは文字列の終わりまで貪欲ではない一致します。
(?=,|$)
パターンは、コンマまたはストリングの終わりで終了する必要があります。
私が間違ったことを理解し始めたとき、ルックアラウンドがこれをどのように複雑にしているかを理解し始めました。ようやく、一致するすべてのテキストが必要なわけではなく、その中に特定のグループが必要であることに気付きました。最終的なコンマを先読みしなかったことを除いて、元の正規表現に非常に似たものを使用することになりました。これはもう少し効率的だと思います。これが私の最終コードです。
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が望むものではないことを知っていますが、他の読者にとっては、Strings.replaceメソッドの1つを使用して、OPsの現在の正規表現の結果配列の各要素から引用符を取り除くことができます。