Почему это предположение не работает в Java? - PullRequest
1 голос
/ 02 июля 2011

Я родом из Perl и привык делать что-то вроде следующего, чтобы сопоставлять начальные цифры в строке и выполнять приращение на месте на единицу:

my $string = '0_Beginning';

$string =~ s|^(\d+)(?=_.*)|$1+1|e;

print $string;        # '1_Beginning'

С моим ограниченным знанием Javaвсе не так лаконично:

String string = "0_Beginning";

Pattern p = Pattern.compile( "^(\\d+)(?=_.*)" );

String digit = string.replaceFirst( p.toString(), "$1" ); // To get the digit

Integer oneMore = Integer.parseInt( digit ) + 1;          // Evaluate ++digit

string.replaceFirst( p.toString(), oneMore.toString() );  //

Регулярное выражение здесь не соответствует ... но оно имело место в Perl.

Что я здесь не так делаю?

Ответы [ 2 ]

2 голосов
/ 02 июля 2011

Давайте посмотрим, что вы здесь делаете.

String string = "0_Beginning";
Pattern p = Pattern.compile( "^(\\d+)(?=_.*)" );

Вы объявляете и инициализируете объекты String и pattern.

String digit = string.replaceFirst( p.toString(), "$1" ); // To get the digit

(Вы преобразуете шаблон обратно в строку, иreplaceFirst создает новый шаблон из этого. Это преднамеренно?)

Как говорит Говард, это заменяет первое совпадение шаблона в строке содержимым первой группы, и совпадение шаблона просто0 здесь, как первая группа.Таким образом, digit равно string, ...

Integer oneMore = Integer.parseInt( digit ) + 1;          // Evaluate ++digit

... и здесь ваш анализ не удастся.

string.replaceFirst( p.toString(), oneMore.toString() );  //

Это будет работать (но преобразовать шаблон сновав строку и обратно в шаблон).

Вот как бы я это сделал:

String string = "0_Beginning";
Pattern p = Pattern.compile( "^(\\d+)(?=_.*)" );

Matcher matcher = p.matcher(string);
StringBuffer result = new StringBuffer();
while(matcher.find()) {
    int number = Integer.parseInt(matcher.group());
    m.appendReplacement(result, String.valueOf(number + 1));
}
m.appendTail(result);
return result.toString(); // 1_Beginning

(Конечно, для вашего регулярного выражения цикл будет выполняться только один раз, поскольку регулярное выражение привязано.)


Редактировать : Чтобы уточнить мое утверждение о string.replaceFirst:

Этот метод не возвращает шаблон, но использует его внутренне. Из документации :

Заменяет первую подстроку этой строки, которая соответствует заданному регулярному выражению с заданной заменой.

Вызов этого метода в форме str.replaceFirst(regex, repl) дает точно такой же результат, как выражение

Pattern.compile(regex).matcher(str).replaceFirst(repl)

Здесь мы видим, что новый шаблон компилируется из первого аргумента.

Это также показывает нам еще один способ сделать то, что вы хотели сделать:

String string = "0_Beginning";
Pattern p = Pattern.compile( "^(\\d+)(?=_.*)" );
Matcher m = p.matcher(string);
if(m.find()) {
    digit = m.group();
    int oneMore = Integer.parseInt( digit ) + 1
    return m.replaceFirst(string, String.valueOf(oneMore));
}

Это скомпилирует шаблон только один раз, а не трижды, как в вашей исходной программе - но все же делаетсовпадение дважды (один раз для поиска, один раз для replaceFirst), а не один раз, как в моей программе.

2 голосов
/ 02 июля 2011

На самом деле это соответствует. Вы можете узнать, напечатав

System.out.println(p.matcher(string).find());

Проблема со строкой

String digit = string.replaceFirst( p.toString(), "$1" );

, который на самом деле ничего не делает, потому что он заменяет первую группу (то есть все, с чем вы совпадаете, предпросмотр не является частью матча) содержимым первой группы.

Вы можете получить желаемый результат (а именно цифру) с помощью следующего кода

Matcher m = p.matcher(string);
String digit = m.find() ? m.group(1) : "";

Примечание: вы должны проверить m.find() в любом случае, если ничего не совпадает. В этом случае вы не можете позвонить parseInt и получите сообщение об ошибке. Таким образом, полный код выглядит примерно так:

Pattern p = Pattern.compile("^(\\d+)(?=_.*)");

String string = "0_Beginning";

Matcher m = p.matcher(string);
if (m.find()) {
    String digit = m.group(1);
    Integer oneMore = Integer.parseInt(digit) + 1;
    string = m.replaceAll(oneMore.toString());
    System.out.println(string);
} else {
    System.out.println("No match");
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...