为什么这个前瞻性断言在Java中不起作用?
我来自Perl背景,习惯于执行如下操作,以匹配字符串中的前导数字,并按1执行就地增量:为什么这个前瞻性断言在Java中不起作用?,java,regex,lookahead,Java,Regex,Lookahead,我来自Perl背景,习惯于执行如下操作,以匹配字符串中的前导数字,并按1执行就地增量: my $string = '0_Beginning'; $string =~ s|^(\d+)(?=_.*)|$1+1|e; print $string; # '1_Beginning' 由于我对Java的了解有限,事情并不是那么简单: String string = "0_Beginning"; Pattern p = Pattern.compile( "^(\\d+)(?=_.*)"
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中实现了
我到底做错了什么?事实上它是匹配的。你可以通过打印找到答案
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 anyways。在这种情况下,您可能无法调用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");
}
事实上它是匹配的。你可以通过打印找到答案
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 anyways。在这种情况下,您可能无法调用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");
}
让我们看看你在这里做什么
String string = "0_Beginning";
Pattern p = Pattern.compile( "^(\\d+)(?=_.*)" );
声明并初始化字符串和模式对象
String digit = string.replaceFirst( p.toString(), "$1" ); // To get the digit
您正在将模式转换回字符串,replaceFirst将从该字符串创建一个新模式。这是故意的吗
正如Howard所说,这将用第一个组的内容替换字符串中模式的第一个匹配项,这里模式的匹配项仅为0,作为第一个组。所以数字等于字符串
。。。你的解析在这里失败了
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.replaceFirstregex形式的此方法,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));
}
这只会编译一次模式,而不是像在原始程序中那样编译三次-但仍然会对find执行两次匹配,对replaceFirst执行一次匹配,而不是像在我的程序中一样执行一次匹配。让我们看看您在这里做什么
String string = "0_Beginning";
Pattern p = Pattern.compile( "^(\\d+)(?=_.*)" );
声明并初始化字符串和模式对象
String digit = string.replaceFirst( p.toString(), "$1" ); // To get the digit
您正在将模式转换回字符串,replaceFirst将从该字符串创建一个新模式。这是故意的吗
正如Howard所说,这将用第一个组的内容替换字符串中模式的第一个匹配项,这里模式的匹配项仅为0,作为第一个组。所以数字等于字符串
。。。你的解析在这里失败了
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.replaceFirstregex形式的此方法,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));
}
这只编译一次模式,而不是像在原始程序中那样编译三次-但仍然会为find执行两次匹配,为replaceFirst执行一次匹配,而不是像在我的程序中一样执行一次匹配。因此,看起来我完全缺少Matcher类。这是我没想到的。现在我回顾一下Perl代码,这有点道理,因为其中涉及到一个模式、一个字符串和一个匹配。匹配在Perl替换中是隐式的,因此,如果匹配,它将替换,如果不匹配,它将不会做任何事情。这是我没想到的。现在我回顾一下Perl代码,这有点道理,因为其中涉及到一个模式、一个字符串和一个匹配。匹配在Perl替换中是隐式的,因此,如果匹配,则替换,如果不匹配,则不会做任何事情。
首先返回一个模式对象-您能进一步解释一下吗+“但是,我没有说过replaceFirst会返回一个Pattern对象。”。我在答案中添加了一个解释。我不同意你关于string.replaceFirst返回模式对象的说法-你能进一步解释吗+“但是,我没有说过replaceFirst会返回一个Pattern对象。”。我对答案作了解释。