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