簡體   English   中英

使用正則表達式匹配多行文本

[英]Match multiline text using regular expression

我正在嘗試使用 java 匹配多行文本。 當我將Pattern類與Pattern.MULTILINE修飾符一起使用時,我能夠匹配,但我不能用(?m).來匹配(?m).

使用(?m)和使用String.matches的相同模式似乎不起作用。

我確定我錯過了一些東西,但不知道是什么。 我不是很擅長正則表達式。

這是我試過的

String test = "User Comments: This is \t a\ta \n test \n\n message \n";

String pattern1 = "User Comments: (\\W)*(\\S)*";
Pattern p = Pattern.compile(pattern1, Pattern.MULTILINE);
System.out.println(p.matcher(test).find());  //true

String pattern2 = "(?m)User Comments: (\\W)*(\\S)*";
System.out.println(test.matches(pattern2));  //false - why?

首先,您在錯誤的假設下使用了修飾符。

Pattern.MULTILINE(?m)告訴 Java 接受錨點^$以匹配每行的開頭和結尾(否則它們只匹配整個字符串的開頭/結尾)。

Pattern.DOTALL(?s)告訴 Java 也允許點匹配換行符。

其次,在您的情況下,正則表達式失敗,因為您使用的是matches()方法,該方法期望正則表達式匹配整個字符串 - 這當然不起作用,因為(\\\\W)*(\\\\S)*匹配。

因此,如果您只是在尋找以User Comments:開頭的字符串,請使用正則表達式

^\s*User Comments:\s*(.*)

使用Pattern.DOTALL選項:

Pattern regex = Pattern.compile("^\\s*User Comments:\\s+(.*)", Pattern.DOTALL);
Matcher regexMatcher = regex.matcher(subjectString);
if (regexMatcher.find()) {
    ResultString = regexMatcher.group(1);
} 

ResultString將包含User Comments:后的文本User Comments:

這與 MULTILINE 標志無關; 您看到的是find()matches()方法之間的區別。 如果可以在目標字符串中的任何位置找到匹配項,則find()成功,而matches()期望正則表達式匹配整個字符串

Pattern p = Pattern.compile("xyz");

Matcher m = p.matcher("123xyzabc");
System.out.println(m.find());    // true
System.out.println(m.matches()); // false

Matcher m = p.matcher("xyz");
System.out.println(m.matches()); // true

此外, MULTILINE並不意味着您認為它的作用。 許多人似乎得出結論,如果目標字符串包含換行符——也就是說,如果它包含多個邏輯行,則必須使用該標志。 我已經在 SO 上看到了幾個答案,但實際上,該標志所做的只是改變了錨點^$的行為。

通常^匹配目標字符串的開頭,而$匹配結尾(或末尾的換行符之前,但我們暫時將其放在一邊)。 但是,如果字符串包含換行符,您可以通過設置 MULTILINE 標志來選擇^$在任何邏輯行的開頭和結尾進行匹配,而不僅僅是整個字符串的開頭和結尾。

所以忘記MULTILINE意思,只記住它的作用:改變^$錨點的行為。 DOTALL模式最初被稱為“單行”(現在仍然有一些風格,包括 Perl 和 .NET),它總是引起類似的混亂。 我們很幸運,在這種情況下,Java 開發人員使用了更具描述性的名稱,但是“多行”模式沒有合理的替代方案。

在 Perl 中,所有這些瘋狂都開始了,他們承認了他們的錯誤並擺脫了 Perl 6 正則表達式中的“多行”和“單行”模式。 再過二十年,也許世界其他地方也會效仿。

str.matches(regex) 行為類似於Pattern.matches(regex, str)嘗試將整個輸入序列與模式匹配並返回

當且僅當整個輸入序列匹配此匹配器的模式時才為true

matcher.find() 試圖找到與模式匹配的輸入序列的下一個子序列並返回

true當且僅當輸入序列的子序列此匹配的模式匹配

因此問題出在正則表達式上。 請嘗試以下操作。

String test = "User Comments: This is \t a\ta \ntest\n\n message \n";

String pattern1 = "User Comments: [\\s\\S]*^test$[\\s\\S]*";
Pattern p = Pattern.compile(pattern1, Pattern.MULTILINE);
System.out.println(p.matcher(test).find());  //true

String pattern2 = "(?m)User Comments: [\\s\\S]*^test$[\\s\\S]*";
System.out.println(test.matches(pattern2));  //true

因此簡而言之,第一個正則表達式中的(\\\\W)*(\\\\S)*部分與空字符串匹配,因為*表示出現零次或多次,而真正匹配的字符串是User Comments:而不是整個字符串,因為您' d 期待。 第二個失敗,因為它試圖匹配整個字符串,但它不能,因為\\\\W匹配非單詞字符,即[^a-zA-Z0-9_]並且第一個字符是T ,一個單詞字符。

多行標志告訴正則表達式將模式匹配到每一行而不是整個字符串,為了您的目的,通配符就足夠了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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