Регулярные выражения в Java с переменной - PullRequest
4 голосов
/ 06 июля 2010

У меня есть переменная v , которая, возможно, появляется более одного раза подряд в строке. Я хочу сделать так, чтобы все последовательные v s превратились в один v . Например:

String s = "Hello, world!";
String v = "l";

Регулярное выражение получит "Привет, мир!" в "Helo, мир!"

Так что я хочу сделать что-то вроде

s = s.replaceAll(vv+, v)

Но, очевидно, это не сработает. Мысли

Ответы [ 5 ]

17 голосов
/ 06 июля 2010

Давайте итеративно разработаем решение; на каждом этапе мы указываем, в чем заключаются проблемы, и исправляем их, пока не дойдем до окончательного ответа.

Мы можем начать с чего-то вроде этого:

String s = "What???? Impo$$ible!!!";
String v = "!";

s = s.replaceAll(v + "{2,}", v);
System.out.println(s);
// "What???? Impo$$ible!"

{2,} - это синтаксис регулярных выражений для конечного повторения, означающий «по крайней мере 2 из» в этом случае.

Просто так вышесказанное работает, потому что ! не является метасимволом регулярных выражений. Давайте посмотрим, что произойдет, если мы попробуем следующее:

String v = "?";

s = s.replaceAll(v + "{2,}", v);
// Exception in thread "main" java.util.regex.PatternSyntaxException:       
// Dangling meta character '?'

Одним из способов решения проблемы является использование Pattern.quote, так что v воспринимается буквально:

s = s.replaceAll(Pattern.quote(v) + "{2,}", v);
System.out.println(s);
// "What? Impo$$ible!!!"

Оказывается, это не единственное, о чем нам нужно беспокоиться: в замещающих строках \ и $ также являются специальными метасимволами. Это объясняет, почему мы получаем следующую проблему:

String v = "$";
s = s.replaceAll(Pattern.quote(v) + "{2,}", v);
// Exception in thread "main" java.lang.StringIndexOutOfBoundsException:
// String index out of range: 1

Поскольку мы хотим, чтобы v воспринималось буквально как строка замены, мы используем Matcher.quoteReplacement следующим образом:

s = s.replaceAll(Pattern.quote(v) + "{2,}", Matcher.quoteReplacement(v));
System.out.println(s);
// "What???? Impo$ible!!!"

Наконец, повторение имеет более высокий приоритет, чем конкатенация. Это означает следующее:

System.out.println(  "hahaha".matches("ha{3}")    ); // false
System.out.println(  "haaa".matches("ha{3}")      ); // true
System.out.println(  "hahaha".matches("(ha){3}")  ); // true

То есть, если v может содержать несколько символов, вам нужно сгруппировать его перед применением повторения. В этом случае вы можете использовать группу без захвата, поскольку вам не нужно создавать обратную ссылку.

String s = "well, well, well, look who's here...";
String v = "well, ";
s = s.replaceAll("(?:" +Pattern.quote(v)+ "){2,}", Matcher.quoteReplacement(v));
System.out.println(s);
// "well, look who's here..."

Основная информация

  • Для сопоставления произвольной литеральной строки, которая может содержать метасимволы регулярных выражений, используйте Pattern.quote
  • Чтобы заменить произвольной литеральной строкой, которая может содержать метасимволы замены, используйте Matcher.quoteReplacement

Ссылки


Бонусный материал

В следующем примере используются повторение с неохотой, группа захвата и обратные ссылки, смешанные с учетом без учета регистра:

    System.out.println(
        "omgomgOMGOMG???? Yes we can! YES WE CAN! GOAAALLLL!!!!"
            .replaceAll("(?i)(.+?)\\1+", "$1")
    );
    // "omg? Yes we can! GOAL!"

Смежные вопросы

Ссылки

5 голосов
/ 06 июля 2010

Используйте x{2,}, чтобы соответствовать x как минимум дважды.

Чтобы иметь возможность заменить символы специальными значениями для регулярных выражений, вы должны использовать Pattern.quote:

String part = Pattern.quote(v);
s = s.replaceAll(part + "{2,}", v);

Чтобы заменить вещи длиннее одного символа, используйте группы без захвата:

String part = "(?:" + Pattern.quote(v) + ")";
s = s.replaceAll(part + "{2,}", v);
4 голосов
/ 06 июля 2010

Вам нужно объединить две строки "v".

Попробуйте s = s.replaceAll(v + v + "+", v)

3 голосов
/ 06 июля 2010

При использовании регулярных выражений в Java обязательно используйте Pattern.quote и Matcher.quoteReplacement :

package com.example.test;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Regex2 {
    static public void main(String[] args)
    {
        String s = "Hello, world!";
        String v = "l";

        System.out.println(doit(s,v));

        s = "Test: ??r??r Solo ??r Frankenstein!";
        v = "??r";

        System.out.println(doit(s,v));

    }

    private static String doit(String s, String v) 
    {
        Pattern p = Pattern.compile("(?:"+Pattern.quote(v)+"){2,}");

        Matcher m = p.matcher(s);
        StringBuffer sb = new StringBuffer();
        while (m.find())
        {
            m.appendReplacement(sb, Matcher.quoteReplacement(v));
        }
        m.appendTail(sb);
        return sb.toString();
    }
}
2 голосов
/ 06 июля 2010
s = s.replaceAll (v + "+", v)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...