Java 正则表达式匹配器跳过匹配项

Java Regex Matcher skipping the matches

下面是我的 Java 代码,用于删除所有匹配的相邻字母对,但是 Java 匹配器 class.

出现了一些问题

My Approach

我正在尝试查找输入中所有连续的重复字符,例如

aaa, bb, ccc, ddd

接下来用最后匹配的模式替换奇数长度匹配,用 "" 替换偶数长度匹配,即

aaa -> a
bb -> ""
ccc -> c
ddd -> d
s has single occurrence, so it's not matched by the regex pattern and excluded from the substitution

我正在调用 Matcher.appendReplacement 根据组长度(偶数或奇数)有条件地替换输入中匹配的模式。

Code:

public static void main(String[] args) {
        String s = "aaabbcccddds";
        int i=0;
        StringBuffer output = new StringBuffer();
        Pattern repeatedChars = Pattern.compile("([a-z])\1+");
        Matcher m = repeatedChars.matcher(s);
        while(m.find()) {
            if(m.group(i).length()%2==0)
                m.appendReplacement(output, "");
            else
                m.appendReplacement(output, "");
            i++;
        }
        m.appendTail(output);
        System.out.println(output);
    }

输入:aaabbcccddds

实际输出:aaabbcccds(仅将 ddd 替换为 d,但跳过 aaabbccc

预期输出:acds

你可以这样试试:

public static void main(String[] args) {
    String s = "aaabbcccddds";
    StringBuffer output = new StringBuffer();
    Pattern repeatedChars = Pattern.compile("(\w)(\1+)");
    Matcher m = repeatedChars.matcher(s);
    while(m.find()) {
        if(m.group(2).length()%2!=0)
            m.appendReplacement(output, "");
        else
            m.appendReplacement(output, "");
    }
    m.appendTail(output);
    System.out.println(output);
}

和你的类似,但是当只得到第一组时,你匹配第一个字符,你的长度总是0。这就是为什么我引入第二组,即匹配的相邻字符。因为它的长度为 -1,所以我反转了奇偶逻辑,瞧 -

acds

已打印。

您不需要多个 if 语句。尝试:

(?:(\w)(?:\1\1)+|(\w)\2+)(?!\1|\2)

替换为</code></p> <p><a href="https://regex101.com/r/L7Ga3Y/1" rel="nofollow noreferrer">Regex live demo</a></p> <p>Java代码:</p> <pre><code>str.replaceAll("(?:(\w)(?:\1\1)+|(\w)\2+)(?!\1|\2)", "");

Java live demo

正则表达式细分:

  • (?: 非捕获组开始
    • (\w) 抓取一个单词字符
    • (?:\1\1)+匹配偶数个相同字符
    • |
    • (\w) 抓取一个单词字符
    • \2+ 匹配任意数量的相同字符
  • ) 非捕获组结束
  • (?!\1|\2)后面没有前面捕获的字符

PatternMatcherStringBuffer 一起使用:

StringBuffer output = new StringBuffer();
Pattern repeatedChars = Pattern.compile("(?:(\w)(?:\1\1)+|(\w)\2+)(?!\1|\2)");
Matcher m = repeatedChars.matcher(s);
while(m.find()) m.appendReplacement(output, "");
m.appendTail(output);
System.out.println(output);

这可以在单个 replaceAll 调用中完成,如下所示:

String repl = str.replaceAll( "(?:(.)\1)+", "" );

正则表达式 (?:(.)\1)+ 匹配所有出现的偶数重复并将其替换为空字符串,这使我们得到奇数重复的第一个字符。

RegEx Demo


代码使用 PatternMatcher:

final Pattern p = Pattern.compile( "(?:(.)\1)+" );
Matcher m = p.matcher( "aaabbcccddds" );
String repl = m.replaceAll( "" );
//=> acds