3

特定の単語のパターンに一致する正規表現を Java で作成して、同じパターンを持つ他の単語を見つけようとしています。たとえば、「tooth」という単語は、「t」と「o」の両方が繰り返されるため、パターン 12213 を持ちます。正規表現を「歯」などの他の単語と一致させたいと思います。

これが後方参照を使用した私の試みです。この特定の例では、2 番目の文字が最初の文字と同じ場合、失敗するはずです。また、最後の文字は他のすべての文字とは異なる必要があります。

String regex = "([a-z])([a-z&&[^\1]])\\2\\1([a-z&&[^\1\2]])";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher("tooth");

//This works as expected
assertTrue(m.matches());

m.reset("tooto");
//This should return false, but instead returns true
assertFalse(m.matches());

最後のグループ、つまり次のグループを削除すると、「toot」のような例で機能することを確認したので、この時点まで後方参照が機能していることがわかります。

String regex = ([a-z])([a-z&&[^\1]])\\2\\1";

しかし、パターンの最後に最後のグループを追加すると、角括弧内の後方参照が認識されなくなります。

私は何か間違ったことをしていますか、それともこれはバグですか?

4

2 に答える 2

4

これを試して:

(?i)\b(([a-z])(?!\2)([a-z])\3\2(?!\3)[a-z]+)\b

説明

(?i)           # Match the remainder of the regex with the options: case insensitive (i)
\b             # Assert position at a word boundary
(              # Match the regular expression below and capture its match into backreference number 1
   (              # Match the regular expression below and capture its match into backreference number 2
      [a-z]          # Match a single character in the range between “a” and “z”
   )
   (?!            # Assert that it is impossible to match the regex below starting at this position (negative lookahead)
      \2             # Match the same text as most recently matched by capturing group number 2
   )
   (              # Match the regular expression below and capture its match into backreference number 3
      [a-z]          # Match a single character in the range between “a” and “z”
   )
   \3             # Match the same text as most recently matched by capturing group number 3
   \2             # Match the same text as most recently matched by capturing group number 2
   (?!            # Assert that it is impossible to match the regex below starting at this position (negative lookahead)
      \3             # Match the same text as most recently matched by capturing group number 3
   )
   [a-z]          # Match a single character in the range between “a” and “z”
      +              # Between one and unlimited times, as many times as possible, giving back as needed (greedy)
)
\b             # Assert position at a word boundary

コード

try {
    Pattern regex = Pattern.compile("(?i)\\b(([a-z])(?!\\2)([a-z])\\3\\2(?!\\3)[a-z]+)\\b");
    Matcher regexMatcher = regex.matcher(subjectString);
    while (regexMatcher.find()) {
        for (int i = 1; i <= regexMatcher.groupCount(); i++) {
            // matched text: regexMatcher.group(i)
            // match start: regexMatcher.start(i)
            // match end: regexMatcher.end(i)
        }
    } 
} catch (PatternSyntaxException ex) {
    // Syntax error in the regular expression
}

ここで再生をご覧ください。お役に立てれば。

于 2012-07-19T05:13:46.740 に答える
4

正規表現を印刷すると、何が問題なのか手がかりが得られます.グループ内の後方参照は、Javaによって実際にエスケープされ、奇妙な文字が生成されます. したがって、期待どおりに動作しません。例えば:

m.reset("oooto");
System.out.println(m.matches());

も印刷します

真実

また、&&正規表現では機能しません。代わりに先読みを使用する必要があります。この式は、上記の例で機能します。

String regex = "([a-z])(?!\\1)([a-z])\\2\\1(?!(\\1|\\2))[a-z]";

(?!\\1)は、正規表現カーソルを前方に移動せずに、次の文字が式の最初の文字ではないことを確認します。

于 2012-07-19T05:15:22.113 に答える