[英]Why isn't this lookahead assertion working in Java?
我來自 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 中匹配。
我在這里做錯了什么?
其實是相配的。 您可以通過打印了解
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");
}
讓我們看看你在這里做什么。
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 的聲明:
此方法不返回模式,而是在內部使用一個模式。 從文檔中:
用給定的替換替換此字符串中與給定正則表達式匹配的第一個 substring。
調用
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));
}
這只會編譯一次模式,而不是像在原始程序中那樣編譯三次 - 但仍然會匹配兩次(一次用於 find,一次用於replaceFirst
),而不是像我的程序中那樣一次。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.