正則指引之匹配模式

jopen 9年前發布 | 12K 次閱讀 正則表達式 Java開發

所謂匹配模式(match mode),指的是匹配時使用的規則。設置特定的模式,可能會改變對正則表達式的識別,也可能會改變正則表達式中字符的匹配規定。常用的匹配模式一共有4種:不區分大小寫模式單行模式多行模式注釋模式

不區分大小寫模式

在看這個模式的應用實例之前,必須首先了解模式的指定方式。通常,有兩種辦法指定匹配模式以模式修飾符指定,或者以預定義的常量作為特殊參數傳入來指定。模式修飾符即模式對應的單個字符,使用時將其填入特定結構(?modifier)中(其中的modifier為模式修改符),嵌在正則表達式的開頭。比如不區分大小寫的匹配模式對應的模式修飾符 i (case Insensitive),對 the 指定此模式,完整的正則表達式就是 (?i)the 。另一種指定模式的方式是使用預定義的常量作為參數,傳入正則函數。在Java中,屬于Pattern類。下表展示了常用語言中不區分大小寫模式的預定義常量:

語言                                              
常量                                                                        
.NET
RegexOptions.IgnoreCase
Java
Pattern.CASE_INSENSITIVE
JavaScript
/regex/i
PHP
/regex/i
Python
re.I
re.IGNORECASE
Ruby
Regexp::IGNORECASE
/regex/i

以Java為例:

//不區分大小寫模式
String text1 = "aaa AAA aaaaa AAAA";
Pattern p1 = Pattern.compile("\\b(a{3,5})\\b",Pattern.CASE_INSENSITIVE);
Matcher m1 = p1.matcher(text1);
while(m1.find()){
    System.out.println(m1.group(1));
}
//不區分大小寫模式(使用模式修飾符)
String text1 = "aaa AAA aaaaa AAAA";
Pattern p1 = Pattern.compile("(?i)\\b(a{3,5})\\b");
Matcher m1 = p1.matcher(text1);
while(m1.find()){
    System.out.println(m1.group(1));
}

單行模式

元字符點號(.幾乎能匹配任何字符,唯有換行符 \n 是例外。但是,有時候確實需要匹配“任何字符”,比如在處理HTML源代碼時,經常會遇到跨越多行的腳本代碼:

<script type="text/javascript">
...code....
...code....
</script>

正則文檔里一般都會說明“點號不能匹配換行符”,不過許多人并不習慣仔細閱讀文檔,所以認為點號 . 能匹配任何字符,當然也就包括換行符,所以直接的想法是用<script\s.*?</script>來匹配。接下來你就會發現最多只能進行到第一行末尾。之前提到過,可以用[\s\S]之類的字符組匹配“任意字符”,所以正則表達式<script\s[\s\S]*?</script>能解決問題。

不過對大多數人來說,點號更加自然,也更簡潔,所以正則表達式提供了單行模式。在這種模式下,所有文本似乎只在一行里,換行符是這一行中的“普通字符”,所以可以由點號 . 匹配。單行模式對應的模式修飾符s (Single line),所以如果用模式修飾符,可以在表達式的開頭用(?s)指定:

//單行模式(使用模式修飾符)
String text1 = "<script tyte='text/javascript'>dddddddddd\r\nrrrrrrrrrrrr</script>";
Pattern p1 = Pattern.compile("(?s)<script\\s.*?</script>");
Matcher m1 = p1.matcher(text1);
while(m1.find()){
    System.out.println(m1.group());
}
//單行模式(使用叁數)
String text1 = "<script tyte='text/javascript'>dddddddddd\r\nrrrrrrrrrrrr</script>";
Pattern p1 = Pattern.compile("<script\\s.*?</script>",Pattern.DOTALL);
Matcher m1 = p1.matcher(text1);
while(m1.find()){
    System.out.println(m1.group());
}

常用語言中單行模式的預定義常量:

語言                                                   
常量                                                                    
.NET
RegexOptions.Singleline
Java
Pattern.DOTALL
JavaScript
不支持此模式
PHP
/regex/s
Python
re.S
re.DOTALL
Ruby
Regexp::MULTILINE
/regex/m

你可能注意到了,單行模式在不同語言中的稱呼很不一樣。比如在Java和Python中叫 DOTALL(也就是點號通配),這個名字確實更高明。不過,“單行模式”成了約定俗成的稱呼。

多行模式

單行模式影響的是點號的匹配規則:在默認模式下,點號 . 可以匹配除換行符之外的任何字符,在單行模式下,點號 . 可以匹配包括換行符在內的任何字符;多行模式影響的是^和$的匹配規則:在默認模式下,^和$匹配的是整個字符串的起始位置和結束位置,但在多行模式下,它們也能匹配字符串內部某一行文本的起始位置和結束位置。

假設,需要找到下面文本中所有數字字符開頭的行:

1 line

NO digit

2 line

解決這個問題,需要定位到每行的起始位置,嘗試匹配一個數字字符,如果成功,則匹配之后的整行文本。多行模式的模式修飾符 m (Multiline),所以在表達式的開頭用(?m)指定多行模式,這樣^可以定位到字符串內部每一行的起始位置;匹配數字字符的表達式是 \d ,因為沒有指定單行模式,點號 . 不能匹配換行符,.*可以匹配“之后的整行文本”,整個表達式就是 (?m)^\d.* 。示例:

//多行模式(使用修飾符)
String text1 = "1 line\r\nNo digit\r\n2 line";
Pattern p1 = Pattern.compile("(?m)^\\b\\d+\\b");
Matcher m1 = p1.matcher(text1);
while(m1.find()){
    System.out.println(m1.group());
}
//多行模式(使用參數)
String text1 = "1 line\r\nNo digit\r\n2 line";
Pattern p1 = Pattern.compile("^\\b\\d+\\b",Pattern.MULTILINE);
Matcher m1 = p1.matcher(text1);
while(m1.find()){
    System.out.println(m1.group());
}

下表列出常用語言中預定義常量的寫法:

語言                                                     
常量                                                                                
.NET
RegexOptions.Multiline
Java
Pattern.NULTILINE
JavaScript
/regex/m
PHP
/regex/m
Python
re.M
re.MULTILINE
Ruby
默認即為多行模式

注釋模式

有時,用到的正則表達式可能非常復雜,不但難以編寫和閱讀,也難以維護。如果正則表達工也像程序源代碼一樣,可以添加注釋,閱讀和維護就容易多了。為了解決這個問題,許多語言支持使用 (?#comment)的記法添加注釋,comment就是注釋的內容。所以,這樣的表達式:^\d.*?$,就可以寫成這樣:

^(?#start of the line)\d(?#digit).*(?#sest of the line)

.NET,Python,Ruby,PHP都支持這種記法,Java與javascript則不支持

來自:http://my.oschina.net/fhd/blog/370714

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!