1. 程式人生 > >常用正則表示式(?i)忽略字母的大小寫!

常用正則表示式(?i)忽略字母的大小寫!

1^/d+$  //匹配非負整數(正整數 + 0) 2^[0-9]*[1-9][0-9]*$  //匹配正整數 3^((-/d+)|(0+))$  //匹配非正整數(負整數 + 0) 4^-[0-9]*[1-9][0-9]*$  //匹配負整數 5^-?/d+$    //匹配整數 6^/d+(/./d+)?$  //匹配非負浮點數(正浮點數 + 0) 7^(([0-9]+/.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*/.[0-9]+)|([0-9]*[1-9][0-9]*))$  //匹配正浮點數 8^((-/d+(/./d+)?)|(0+(/.0+)?))$  //匹配非正浮點數(負浮點數 + 0) 9^(-(([0-9]+/.[0-9]

*[1-9][0-9]*)|([0-9]*[1-9][0-9]*/.[0-9]+)|([0-9]*[1-9][0-9]*)))$  //匹配負浮點數 10^(-?/d+)(/./d+)?$  //匹配浮點數 11^[A-Za-z]+$  //匹配由26個英文字母組成的字串 12^[A-Z]+$  //匹配由26個英文字母的大寫組成的字串 13^[a-z]+$  //匹配由26個英文字母的小寫組成的字串 14^[A-Za-z0-9]+$  //匹配由數字和26個英文字母組成的字串 15^/w+$  //匹配由數字、26個英文字母或者下劃線組成的字串 16^[/w-]+(/.[/w-]+)*@[/w-]+(/.[/w-]+)+$    //匹配email地址 
17^[a-zA-z]+://匹配(/w+(-/w+)*)(/.(/w+(-/w+)*))*(/?/S*)?$  //匹配url 18。匹配中文字元的正則表示式: [/u4e00-/u9fa5]
19。匹配雙位元組字元(包括漢字在內):[^/x00-/xff]
20。應用:計算字串的長度(一個雙位元組字元長度計2,ASCII字元計1)
String.prototype.len
=function(){returnthis.replace([^/x00-/xff]/g,"aa").length;}
21。匹配空行的正則表示式:/n[/s| ]*/r
22。匹配HTML標記的正則表示式:/<(.*)>.*<///1>|<(.*) //>/23
。匹配首尾空格的正則表示式:(^/s*)|(/s*$)

* 正則表示式用例
  
*1^/S+[a-z A-Z]$ 不能為空 不能有空格  只能是英文字母
  
*2、/S{6,}         不能為空 六位以上
  
*3^/d+$          不能有空格 不能非數字
  
*4、(.*)(/.jpg|/.bmp)$ 只能是jpg和bmp格式
  
*5^/d{4}/-/d{1,2}-/d{1,2}$ 只能是2004-10-22格式
  
*6^0$            至少選一項
  
*7^0{2,}$        至少選兩項
  
*8^[/s|/S]{20,}$ 不能為空 二十字以上
  
*9^/+?[a-z0-9](([-+.]|[_]+)?[a-z0-9]+)*@([a-z0-9]+(/.|/-))+[a-z]{2,6}$郵件
  
*10、/w+([-+.]/w+)*@/w+([-.]/w+)*/./w+([-.]/w+)*([,;]/s*/w+([-+.]/w+)*@/w+([-.]/w+)*/./w+([-.]/w+)*)* 輸入多個地址用逗號或空格分隔郵件
  
*11^(/([0-9]+/))?[0-9]{7,8}$電話號碼7位或8位或前面有區號例如(02287341628*12^[a-z A-0-9 _]+@[a-z A-0-9 _]+(/.[a-z A-0-9 _]+)+(/,[a-z A-0-9 _]+@[a-z A-0-9 _]+(/.[a-z A-0-9 _]+)+)*$
  
*     只能是字母、數字、下劃線;必須有@和.同時格式要規範 郵件
  
*13^/w+@/w+(/./w+)+(/,/w+@/w+(/./w+)+)*$上面表示式也可以寫成這樣子,更精練。
    
14^/w+((-/w+)|(/./w+))*/@/w+((/.|-)/w+)*/./w+

  

  

  

// 限定條件final String CONDITION ="(?=.*[a-z])(?=.*[A-Z])(?=.*//d)";

        
// 允許出現的字元final String SPECIAL_CHAR ="[-A-Za-z0-9!$%&()/;<?{}//[//]^////]";

        
// 數量final String QUANTITY ="{8,16}"

  

1 樓的回覆

(
?=.*[a-z]) 表示當前位置後面必須出現 .*[a-z] 的字元,這個可以理解為必須出現小寫字母。
或者可以理解為某一個字元間的縫隙必須滿足的條件,這個僅僅作為條件判斷並不能匹配任何字
符,因為這屬於非捕獲組中的環視(lookarround)零寬度匹配。

舉個大家常見的例子:

表示式:Win(
?=XP)
現有字串 WinXP 和 WinNT,在應用這個表示式時前者能與之進行匹配,為什麼呢?

當匹配器指示到 (
?=XP) 時,也就是在 n 字母后面的縫隙,這個縫隙必須滿足的
條件是:後面的字元必須是 XP,如果是的話,匹配成功,否則匹配失敗。由於
(
?=XP) 是匹配縫隙的,因此並不會把 XP 給匹配輸出,而只輸出了 Win 因此,這
個表示式的語義可以看作是:找到後面為“XP”字元所有的 Win。

假如,我們把表示式寫成 Win(
?=XP)(?=NT) 這樣的話,那麼這個語義是:找出後面
為“XP”並且為“NT”字元所有的 Win 可以想象,這是個
永遠無法滿足的匹配。(
?=XP)(?=NT) 這個表示當前的縫隙必須同時滿足的條件。

把這個表示式再改一下,改成 Win(
?=.*XP)(?=.*NT) 這個表示 Win 的後面必須出現
XP 與 NT,位置和順序都是無關的(這主要是 .
* 的作用)。當然了這個表示式的效
率是比較低的,得向後進行兩次斷言。

如果字串是 WincbaXPabcNT 這個字串,當匹配指示器走到 n 後面的縫隙時開始
進行向後斷言,首先對 .
*XP 進行斷言,很明顯能將 cbaXP 匹配成功,這時第一個斷
言完成,再對 .
*NT 斷言,可以看出 cbaXPabcNT 能與其匹配成功,這時第二個斷言完
成,因此表示式 Win(
?=.*XP)(?=.*NT) 能對 WincbaXPabcNT 進行匹配。

同理 WincbaNTabcXP 也是同樣的效果。

如果能理解上面的這些,對於 (
?=.*[a-z])(?=.*[A-Z])(?=.*//d) 這個的理應該不會
很難吧,這個只不過是必須同時滿足三個條件。

這個表示式在開始部分就進行斷言,即索引為 
0 的地方,也就是第一個字元的前面的
縫隙,這個縫隙後面的字元必須滿足 .
*[a-z]  .*[A-Z]  .*//d  三個條件,也就是說
必後面必須出現至少一個小寫字母、至少一個大寫母、至少一個數字。


至於表示式 
2 的使用,也就是 [  ] 內字元的轉義需要注意一下。

^ 和 - 在 [  ] 結構的表示式中是有一定意義的。

[
^abc] 表示除 abc 以外所有的字元,注意,這是放在最前面表示這個意思,
如果改成 [a
^bc] 這個僅表示 a ^ b c 四個字元。如果需要匹配 ^ 這個字元
的話,千萬不要把它放在第一個,如果一定要放在第一個的話,得使用轉義符。

- 在 [  ] 表示字元的範圍,比如 [a-z] 表示 a 與 z 之間的 26 個字母,
[a
-zA-Z] 這個表示 a-z 和 A-Z 的 52 個字母。使用範圍得注意了,如果寫成
[z
-a] 的話,在 Pattern.compile 編譯表示式時會對範圍進行檢查,這時會產
生異常,因此在使用 
- 範圍時,後面的 Unicode 值必須大於等於前面的 Unicode
值。

如果要匹配“
-”的話,儘量不要把 - 這個放在字元之間,可以放在 [  ] 的兩邊。
比如 [
-a-z] 這就能匹配 26 個小寫字母和“-”了。當然了,我們也可以寫成
[a
-z-A-Z] 這個可以匹配 52 字母和“-”,但是這樣很不直觀,我們寧願寫成
[a
-zA-Z-] 或者 [-a-zA-Z] 這樣。 

  

  

2:不以某某開頭 ,比如不以www開頭


Java code 
publicclass Test { 
    
publicstaticvoid main(String[] args) {
        String[] strs 
= { "abc1232""wwwadsf""awwwfas""wwadfsf""""ww""""www" }; 
        String regex 
="(?:(?!^www).)*"
        
for(String str : strs) { 

            System.out.printf(
"%-7s %s%n", str, str.matches(regex));
        }
    }



(
?!X) 專業名稱為 Negative Lookahead,表示字元間縫隙後面不允許出現的字元,
即匹配字元間的縫隙,如果縫隙後的字元不是 X 的話,那這個縫隙就匹配成功。

舉個例子,aab 和 aac,現有表示式 aa(
?!b) 這時我們能匹配到的字串是 aac,
因為 aa 的後面的縫隙之後不允許出現字元 b,因此只有 aac 進行了匹配。

再來看個示例: 

Java code 

publicclass Test {
    
publicstaticvoid main(String[] args) {
        String str 
="AQuickBrownFoxJumpsOverTheLazyDog";
        String[] strs 
= str.split("(?<!^)(?=[A-Z])");
        
for(String s : strs) {
            System.out.println(s);
        } 
    }



根據大寫字母拆分字串。當然了,這個使用字串進行分析同樣也能進行拆分,
但是使用正則表示式來拆的話更為便捷直觀一些。

在進行這種拆分時,由於在拆分後的字元數不能減少,因此只能使用零寬度的
lookaround 功能進行匹配,lookaround 包括四個,即: 

Java code 
(
?=X) (?!X) (?<=X) (?<!X) 


來看一下這個表示式:(
?<!^)(?=[A-Z])

前面說到過 (
?!) 表示縫隙後面不允許出現的東西,而 (?<!) 表示縫隙前不允許出現的東西。
(
?=) 表示縫隙後允許出現的東西,(?<=) 表示縫隙前允許出現的東西。

這個表示式在拆分時,根據零寬度匹配縫隙進行拆分的,這個縫隙必須滿足以下條件:

(
?<!^) 表示縫隙不允許前不能是行開始,即縫隙不能出現在首字母的前面。
(
?=[A-Z]) 表示縫隙後面允許出現 A-Z 的大寫字母。

這時這個表示式就匹配了下面帶有 
| 的縫隙: 

Java code 
A
|Quick|Brown|Fox|Jumps|Over|The|Lazy|DogPS:不加 (?<!^) 的話,會變成:|A|Quick|Brown|Fox|Jumps|Over|The|Lazy|Dog 


根據 split 的功能,正則表示式處理程式就根據上面的 
| 將字串給拆分開來了。


3,不區分大小寫
不加任何限制的匹配是匹配分大小寫的,但是正則表示式中可以進行改變,
有兩種方式:引數式和內嵌式。

來看個示例: 

Java code 
import java.util.regex.Matcher;
import java.util.regex.Pattern;
publicclass Test {
    
publicstaticvoid main(String[] args) {
        String str 
="Book"
        Pattern pattern 
= Pattern.compile("book");
        Matcher matcher 
= pattern.matcher(str);
        System.out.println(matcher.matches()); 
    }



上面的這個表示式 book 是不能匹配字串 Book 的,這時我們只要給定編譯時的引數就可以了:

Pattern pattern 
= Pattern.compile("book", Pattern.CASE_INSENSITIVE);

Pattern.CASE_INSENSITIVE 這是一個 
int 型別的常量,值為 2。表示表示式忽略大小寫進行區配。

如果我們不採用 Pattern 和 Matcher 兩個類來匹配的話,只是使用 String 的 matches 方法的話,
我們就不能指定表示式的編譯引數了,這時就需要採用內嵌標誌表示式了,與 Pattern.CASE_INSENSITIVE
對應的內嵌標誌表示式是 (
?i),它有四種形式:
1,(?i)
2,(?-i)
3,(?i:X)
4,(?-i:X)
不帶有 
- 的是開標誌,帶有 - 的是關標誌。

把上面的程式碼改成這樣: 

Java code 
publicclass Test {
    
publicstaticvoid main(String[] args) {
        String str 
="Book";
        String regex 
="(?i)book"
        System.out.println(str.matches(regex));
    }



我們就達到了同樣的效果,當然這樣並不是最好的,因為字串中只有 B 是大寫的,
我們沒有必要把所有的字元都進行不區分大小寫匹配,我們可以在開啟標誌,用 (
?i) 的
第二種形式馬上關掉它:
    String regex 
="(?i)b(?-i)ook";

這樣的話,只有 b 是區分大小寫了,而 (
?-i) 後面的還是得區分大小寫匹配的。這樣寫
可能看上去很不順眼,我們還能使用第 
3 種形式直接指定某些字元是不區分大小寫的。
    String regex 
="(?i:b)ook";

這樣的表示式與上面的那個在語義上是相同的。就效率上肯定是優於一下子開,一下子關的。

可見內嵌標誌表示式要比指定編譯引數的功能強大許多。

使用建議:如果能確定某些字元的大小寫時,儘量使用已確定的字元,對於不確定的可以採用
(
?i:X) 的方式指定。因此開啟不區分大小寫開關時,對匹配的效能是有一定影響的。

思考一下:String regex 
="(?i)b(?-i:oo)k"; 這個表示式的意思?


另外:第 
1 和第 4,我沒看明白需要了解什麼,請在下面的樓層中具體地說明一下。 

  

1:多行匹配

在預設的情況下 . 是不能匹配行結束符的(行結束符有 
6 個,具體的可以看看 Pattern 的 API DOC)
同樣,可以像不匹配大小寫匹配那樣使用編譯引數:Pattern.DOTALL

如果還得區分大小寫的話,還得加上上面說到的 Pattern.CASE_INSENSITIVE 這個,舉個例子: 

Java code 
import java.util.regex.Matcher;
import java.util.regex.Pattern;
publicclass Test {
    
publicstaticvoid main(String[] args) {
        String str 
="<table> /n"+" <tr> /n"+" <td> /n"+" Hello World! /n"+" </td> /n"+" </tr> /n"+"</table>";
        String regex 
="<td>(.+?)</td>"
        Pattern pattern 
= Pattern.compile(regex);
        Matcher matcher 
= pattern.matcher(str);
        
while(matcher.find()) { 
            System.out.println(matcher.group(
1).trim()); 
        }
    }



上面這個是不能從 str 抽取出東西的,因為 td 的後面帶有換行符,我們只要更改一下:

Pattern pattern 
= Pattern.compile(regex, Pattern.DOTALL);

這樣就行了,如果 td 還得不區分大小寫的話,再改成: 

Java code 
Pattern pattern 
= Pattern.compile(regex, Pattern.DOTALL | Pattern.CASE_INSENSITIVE); 


這樣的話,td 哪怕是大寫的這個表示式都能把 td 之間的字元區抽取出來。

當然和 Pattern.CASE_INSENSITIVE 一樣,Pattern.DOTALL 也有內嵌標誌表示式,即 (
?s)
s 的意思表示 single
-line 就是忽略換行符什麼的,只看成單行進行處理。

這個表示式使用內嵌 (
?s) 的話可以改為: 

Java code 
String regex 
="(?s)<td>(.+?)</td>";如果還要不區分大小寫的話,再加上 i 標誌:String regex ="(?s)(?i)<td>(.+?)</td>";但這樣顯得很拖沓,可以把它們合併起來:String regex ="(?is)<td>(.+?)</td>"// 秩序無所謂 

最後需要說明一下的是,我曾看到過由於不明白 DOTALL,為了讓 . 匹配行結束符,直接把表示式寫成: 

Java code 
String regex 
="<td>((.|//s)+?)</td>"


這樣做是極其危險的,由於選擇結構的匹配效率問題,這樣做在比較長的字串時會造成堆疊溢位,
使程式崩潰,如果使用 DOTALL 或者 (
?s) 的話就不會出現這種情況。


4:2個單元的或操作

| 稱為多選結構,用於匹配 | 之中的任何一個,拿你的例子來說明: 

Java code 
import java.util.regex.Matcher;
import java.util.regex.Pattern;
publicclass Test { 
    
publicstaticvoid main(String[] args) { 
        String str 
="<img src=/"http://www.google.com/1.gif/"/>/n" + "<img src=/"http://3w.google.com/1.gif/"/>/n" + "<img src=/"http://abc.baidu.com/1.gif/"/>";        String regex ="<img//ssrc=/"http://(?:ww|3)w.google.com/1.gif/"/>";        Pattern pattern = Pattern.compile(regex);
        Matcher matcher 
= pattern.matcher(str); 
        
while(matcher.find()) { 
            System.out.println(matcher.group()); 
        } 
    }



注意到其中的 (
?:ww|3) 在進行多選匹配時儘量找出多選中的規律,以減少多選的字元,
www 和 3w 在最後一個字元可以共用,前面的不一樣。

(
?: ) 的意思表示組成一組,如果沒有 (?: ) 這樣的話,表示式就變成了: 

Java code 
String regex 
="<img//ssrc=/"http://ww|3w.google.com/1.gif/"/>"; 

這樣的語義完全變掉了,
| 是在一組中進行選擇,由於上面的那個表示式中沒有組,就把整個表
達式作為了一組,使用 
| 的話,就進行了整個表示式的多選結構了。這個表示式的意思是:
匹配 
<img ssrc="http://ww 或者是 3w.google.com/1.gif"/>,這樣的結果並不是我們所要的。

我們僅僅需要在 ww 和 
3 之間進行選擇,這時只要把 ww 和 3 放在一組中進行多選擇就可以了,
變成 (
?:ww|3)。

還有,在多選結構中儘量把出現頻率高的放在前面,這樣可以加快匹配速度。

多選結構的效率在傳統型的引擎中是效率低下的,如果是單個字元的選擇,比如 a $ 
& 之中的一個,
那就不要使用 (
?:a|$|&) 了,可以直接使用字元類 [a$&] 就可以了。

說了那麼多,不知道是否明白了?