簡體   English   中英

為什么這個前瞻斷言在 Java 中不起作用?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM