为什么这个先行断言在 Java 中不起作用?

发布于 2024-11-18 13:42:54 字数 597 浏览 8 评论 0原文

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

我在这里做错了什么?

I come from a Perl background and am used to doing something like the following to match leading digits in a string and perform an in-place increment by one:

my $string = '0_Beginning';

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

print $string;        # '1_Beginning'

With my limited knowledge of Java, things aren't so succinct:

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() );  //

The regex doesn't match here... but it did in Perl.

What am I doing wrong here?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

叫思念不要吵 2024-11-25 13:42:54

其实很匹配。您可以通过打印来找

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");
}

Actually it matches. You can find out by printing

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

The issue is with line

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

which is actually a do-nothing, because it replaces the first group (which is all you match, the lookahead is not part of the match) with the content of the first group.

You can get the desired result (namely the digit) via the following code

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

Note: you should check m.find() anyways if nothing matches. In this case you may not call parseInt and you'll get an error. Thus the full code looks something like

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");
}
枉心 2024-11-25 13:42:54

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

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

您声明并初始化 String 和模式对象。

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

(您将模式转换回字符串,replaceFirst 从中创建一个新模式。这是故意的吗?)

正如 Howard 所说,这会将字符串中模式的第一个匹配项替换为第一组的内容,并且模式的匹配在这里只是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)

Here 完全相同的结果,我们看到从第一个参数编译了一个新模式。

这也向我们展示了另一种方法来完成您想做的事情:

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

Let's see what you are doing here.

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

You declare and initialize String and pattern objects.

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

(You are converting the pattern back into a string, and replaceFirst creates a new Pattern from this. Is this intentional?)

As Howard says, this replaces the first match of the pattern in the string with the contents of the first group, and the match of the pattern is just 0 here, as the first group. Thus digit is equal to string, ...

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

... and your parsing fails here.

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

This would work (but convert the pattern again to string and back to pattern).

Here how I would do this:

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

(Of course, for your regex the loop will only execute once, since the regex is anchored.)


Edit: To clarify my statement about string.replaceFirst:

This method does not return a pattern, but uses one internally. From the documentation:

Replaces the first substring of this string that matches the given regular expression with the given replacement.

An invocation of this method of the form str.replaceFirst(regex, repl) yields exactly the same result as the expression

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

Here we see that a new pattern is compiled from the first argument.

This also shows us another way to do what you did want to do:

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));
}

This only compiles the pattern once, instead of thrice like in your original program - but still does the matching twice (once for find, once for replaceFirst), instead of once like in my program.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文