在使用正則表達式的場合,經常有這種需求,就是匹配一個不包含某個子串的子符串。好比說,我要從「eabcdfgh」獲得"cd"以前的子串。有些人可能會寫:正則表達式
([^cd]*)ide
這種寫法是完全錯誤的,由於[]中的是集合,也就是說,[^cd]表示不等於c或者d,而不是cd。下面的程序中沒有cd,但eab仍是被匹配出來了。spa
- String s = "([^cd]*)";
- Match m = Regex.Match("eabcfgh", s);
- MessageBox.Show(m.Value);//eab
- MessageBox.Show(m.Groups[1].Value);//eab
上面這種寫法是錯的比較離譜的,正常青年通常均可以免這種錯誤。在特殊狀況下,正則表達式能夠這麼寫,並且效率是比較高的。字符串
([/s/S]*cd)get
先說明下/s/S是表示匹配任何字符。所謂特殊狀況,就是我知道這個字符串中必有cd的存在。假如,個人要求是匹配不包含cd的部分(爲了描述方便,只匹配cd以前的部分),也就是說,當cd不存在時,應該把整個字符串都取出來。string
- String s = "((.(?!cd))*.)";
- //String s = "([/s/S]*cd)";
- Match m = Regex.Match("eabcdfgh", s);
- MessageBox.Show(m.Value);//eab
- MessageBox.Show(m.Groups[1].Value);//eab
這種寫法終於符合要求了。不過值得一提的是,相較前一種而言,它的效率比較低。it
回顧一下相關的語法:class
(?:子表達式) 定義非捕獲組。效率
- //定義非捕獲組
- String s = "e(?:ab)(.*)";
- Match m = Regex.Match("eabcd", s);
- MessageBox.Show(m.Value);//eabcd
- MessageBox.Show(m.Groups[1].Value);//cd
ab是被匹配的,可是它所在的組沒有被捕獲,Group[1]是cd語法
(?=子表達式) 零寬度正預測先行斷言。
- //零寬度正預測先行斷言
- //String s = "b(cd|de)(.*)";
- String s = "b(?=cd|de)(.*)";
- Match m = Regex.Match("eabcdfg", s);
- MessageBox.Show(m.Value);
- MessageBox.Show(m.Groups[1].Value);//區別 cd cdfg
這種寫法和註釋掉的寫法是有區別的,區別就是「零寬度」,這種寫法會被捕獲,也就是不佔一個Group。
(?!子表達式) 零寬度負預測先行斷言。
!表示非,就是不包含,一樣是零寬度,不會被捕獲。
(?<=子表達式) 零寬度正回顧後發斷言。
例:(?<=19)\d{2}\b
「1851 1999 1950 1905 2003」中的「99」、「50」和「05」
(?<!子表達式) 零寬度負回顧後發斷言。
例:(?<!19)\d{2}\b
「1851 1999 1950 1905 2003」中的「51」和「03」