正規表現に一致するすべての (重複している可能性がある) 部分文字列を返す API メソッドはありますか?
たとえば、テキスト string:があり、2 つ以上の文字の文字列に一致String t = 04/31 412-555-1235;
する pattern:があります。Pattern p = new Pattern("\\d\\d+");
私が取得した一致は、04、31、412、555、1235 です。
重複する一致を取得するにはどうすればよいですか?
コードが返されるようにしたい: 04, 31, 41, 412, 12, 55, 555, 55, 12, 123, 1235, 23, 235, 35.
理論的には可能O(n^2)
です。パターンに対してすべての部分文字列を列挙してチェックする明らかなアルゴリズムがあります。
編集
すべての部分文字列を列挙するよりも、 のregion(int start, int end)
メソッドを使用する方が安全Matcher
です。別の抽出された部分文字列に対してパターンをチェックすると、一致の結果が変わる可能性があります (たとえば、パターンの開始/終了に非キャプチャ グループまたは単語境界チェックがある場合)。
編集2
実際、region()
ゼロ幅の一致に期待することができるかどうかは不明です。仕様は曖昧であり、実験では期待外れの結果が得られます。
例えば:
String line = "xx90xx";
String pat = "\\b90\\b";
System.out.println(Pattern.compile(pat).matcher(line).find()); // prints false
for (int i = 0; i < line.length(); ++i) {
for (int j = i + 1; j <= line.length(); ++j) {
Matcher m = Pattern.compile(pat).matcher(line).region(i, j);
if (m.find() && m.group().size == (j - i)) {
System.out.println(m.group() + " (" + i + ", " + j + ")"); // prints 90 (2, 4)
}
}
}
最もエレガントなソリューションが何であるかはわかりません。1 つのアプローチは、一致line
するかどうかを確認する前に、の部分文字列を取得し、適切な境界文字を埋め込むことです。pat
編集3
これが私が思いついた完全な解決策です。オリジナルの正規表現でゼロ幅のパターンや境界などを扱うことができます。テキスト文字列のすべての部分文字列を調べ、最初と最後に適切な数のワイルドカードをパターンに埋め込むことによって、正規表現が特定の位置でのみ一致するかどうかを確認します。私が試したケースではうまくいくようですが、広範なテストは行っていません。それは間違いなく、それができるよりも効率が悪いです。
public static void allMatches(String text, String regex)
{
for (int i = 0; i < text.length(); ++i) {
for (int j = i + 1; j <= text.length(); ++j) {
String positionSpecificPattern = "((?<=^.{"+i+"})("+regex+")(?=.{"+(text.length() - j)+"}$))";
Matcher m = Pattern.compile(positionSpecificPattern).matcher(text);
if (m.find())
{
System.out.println("Match found: \"" + (m.group()) + "\" at position [" + i + ", " + j + ")");
}
}
}
}
編集4
これを行うより良い方法は次のとおりです。https://stackoverflow.com/a/11372670/244526
編集5
JRegexライブラリは、Java 正規表現に一致するすべての重複部分文字列の検索をサポートしています (ただし、しばらく更新されていないようです)。具体的には、非互換検索に関するドキュメントでは次のように指定されています。
非破壊検索を使用すると、交差またはネストされたパターンを含む、パターンのすべての可能な発生を見つけることができます。これは、find() の代わりにMatcherのメソッドproceed()を使用することで実現されます