Java Regex Matcher, пропускающий матчи - PullRequest
0 голосов
/ 10 мая 2018

Ниже приведен мой код Java для удаления всех совпадающих пар соседних букв, но у меня возникают некоторые проблемы с классом Java Matcher.

Мой подход

Я пытаюсь найти все последовательные повторяющиеся символы на входе, например

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, чтобы сделать условную замену шаблонов, сопоставленных на входе, на основе длины группы (четной или нечетной).

Код:

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, "$1");
            i++;
        }
        m.appendTail(output);
        System.out.println(output);
    }

Ввод: aaabbcccddds

Фактический вывод: aaabbcccds (только замена ddd на d, но пропуск aaa, bb и ccc)

ОжидаетсяВыход: acds

Ответы [ 3 ]

0 голосов
/ 10 мая 2018

Вам не нужно несколько операторов if.Попробуйте:

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

Заменить на $1

Regex live demo

Java-код:

str.replaceAll("(?:(\\w)(?:\\1\\1)+|(\\w)\\2+)(?!\\1|\\2)", "$1");

Демонстрация Java Live

Распределение регулярных выражений:

  • (?: Начало группы без захвата
    • (\\w) Захватить символ слова
    • (?:\\1\\1)+ Соответствует четному числу одного и того же символа
    • | Или
    • (\\w) Захватите символ слова
    • \\2+ Соответствует любому числутот же символ
  • ) Конец группы без захвата
  • (?!\\1|\\2) За ней не следуют предыдущие захваченные символы

Использование Pattern и Matcher с StringBuffer:

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, "$1");
m.appendTail(output);
System.out.println(output);
0 голосов
/ 10 мая 2018

Это можно сделать за один replaceAll вызов, например:

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

Выражение регулярного выражения (?:(.)\\1)+ сопоставляет все вхождения четных повторений и заменяет его пустой строкой, оставляя нам первый символнечетное количество повторений.

Демонстрация RegEx


Код с использованием Pattern и Matcher:

final Pattern p = Pattern.compile( "(?:(.)\\1)+" );
Matcher m = p.matcher( "aaabbcccddds" );
String repl = m.replaceAll( "" );
//=> acds
0 голосов
/ 10 мая 2018

Вы можете попробовать вот так:

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, "$1");
    }
    m.appendTail(output);
    System.out.println(output);
}

Это похоже на вашу, но когда вы получаете только первую группу, вы соответствуете первому символу, а ваша длина всегда равна 0. Вот почему я представляю вторую группу, котораясовпадающие соседние символы.Поскольку он имеет длину -1, я инвертирую нечетную четную логику и вуаля -

acds

.

...