1

我来自 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 中匹配。

我在这里做错了什么?

4

2 回答 2

2

其实是相配的。您可以通过打印了解

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");
}
于 2011-07-02T15:34:26.800 回答
2

让我们看看你在这里做什么。

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

您声明和初始化字符串和模式对象。

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),而不是像我的程序中那样一次。

于 2011-07-02T15:48:48.583 回答