C# 正則表達式
c# 正則表達式
正則表達式是一種匹配輸入文本的模式。.net 框架提供了允許這種匹配的正則表達式引擎。
模式由一個或多個字符、運算符和結構組成。
如果你還不理解正則表達式可以閱讀我們的正則表達式 - 教程。
1. 定義正則表達式
下面列出了用于定義正則表達式的各種類別的字符、運算符和結構。
- 字符轉義
- 字符類
- 定位點
- 分組構造
- 限定符
- 反向引用構造
- 備用構造
- 替換
- 雜項構造
1) 字符轉義
正則表達式中的反斜杠字符(\)指示其后跟的字符是特殊字符,或應按原義解釋該字符。
下表列出了轉義字符:
轉義字符 | 描述 | 模式 | 匹配 |
---|---|---|---|
\a | 與報警 (bell) 符 \u0007 匹配。 | \a | "warning!" + '\u0007' 中的 "\u0007" |
\b | 在字符類中,與退格鍵 \u0008 匹配。 | [\b]{3,} | "\b\b\b\b" 中的 "\b\b\b\b" |
\t | 與制表符 \u0009 匹配。 | (\w+)\t | "name\taddr\t" 中的 "name\t" 和 "addr\t" |
\r | 與回車符 \u000d 匹配。(\r 與換行符 \n 不是等效的。) | \r\n(\w+) | "\r\nhello\nworld." 中的 "\r\nhello" |
\v | 與垂直制表符 \u000b 匹配。 | [\v]{2,} | "\v\v\v" 中的 "\v\v\v" |
\f | 與換頁符 \u000c 匹配。 | [\f]{2,} | "\f\f\f" 中的 "\f\f\f" |
\n | 與換行符 \u000a 匹配。 | \r\n(\w+) | "\r\nhello\nworld." 中的 "\r\nhello" |
\e | 與轉義符 \u001b 匹配。 | \e | "\x001b" 中的 "\x001b" |
\ nnn | 使用八進制表示形式指定一個字符(nnn 由二到三位數字組成)。 | \w\040\w | "a bc d" 中的 "a b" 和 "c d" |
\x nn | 使用十六進制表示形式指定字符(nn 恰好由兩位數字組成)。 | \w\x20\w | "a bc d" 中的 "a b" 和 "c d" |
\c x \c x | 匹配 x 或 x 指定的 ascii 控件字符,其中 x 或 x 是控件字符的字母。 | \cc | "\x0003" 中的 "\x0003" (ctrl-c) |
\u nnnn | 使用十六進制表示形式匹配一個 unicode 字符(由 nnnn 表示的四位數)。 | \w\u0020\w | "a bc d" 中的 "a b" 和 "c d" |
\ | 在后面帶有不識別的轉義字符時,與該字符匹配。 | \d+[\+-x\*]\d+\d+[\+-x\*\d+ | "(2+2) * 3*9" 中的 "2+2" 和 "3*9" |
2) 字符類
字符類與一組字符中的任何一個字符匹配。
下表列出了字符類:
字符類 | 描述 | 模式 | 匹配 |
---|---|---|---|
[character_group] | 匹配 character_group 中的任何單個字符。 默認情況下,匹配區分大小寫。 | [mn] | "mat" 中的 "m","moon" 中的 "m" 和 "n" |
[^character_group] | 非:與不在 character_group 中的任何單個字符匹配。 默認情況下,character_group 中的字符區分大小寫。 | [^aei] | "avail" 中的 "v" 和 "l" |
[ first - last ] | 字符范圍:與從 first 到 last 的范圍中的任何單個字符匹配。 | [b-d] | [b-d]irds 可以匹配 birds、 cirds、 dirds |
. | 通配符:與除 \n 之外的任何單個字符匹配。 若要匹配原意句點字符(. 或 \u002e),您必須在該字符前面加上轉義符 (\.)。 | a.e | "have" 中的 "ave", "mate" 中的 "ate" |
\p{ name } | 與 name 指定的 unicode 通用類別或命名塊中的任何單個字符匹配。 | \p{lu} | "city lights" 中的 "c" 和 "l" |
\p{ name } | 與不在 name 指定的 unicode 通用類別或命名塊中的任何單個字符匹配。 | \p{lu} | "city" 中的 "i"、 "t" 和 "y" |
\w | 與任何單詞字符匹配。 | \w | "room#1" 中的 "r"、 "o"、 "m" 和 "1" |
\w | 與任何非單詞字符匹配。 | \w | "room#1" 中的 "#" |
\s | 與任何空白字符匹配。 | \w\s | "id a1.3" 中的 "d " |
\s | 與任何非空白字符匹配。 | \s\s | "int __ctr" 中的 " _" |
\d | 與任何十進制數字匹配。 | \d | "4 = iv" 中的 "4" |
\d | 匹配不是十進制數的任意字符。 | \d | "4 = iv" 中的 " "、 "="、 " "、 "i" 和 "v" |
3) 定位點
定位點或原子零寬度斷言會使匹配成功或失敗,具體取決于字符串中的當前位置,但它們不會使引擎在字符串中前進或使用字符。
下表列出了定位點:
斷言 | 描述 | 模式 | 匹配 |
---|---|---|---|
^ | 匹配必須從字符串或一行的開頭開始。 | ^\d{3} | "567-777-" 中的 "567" |
$ | 匹配必須出現在字符串的末尾或出現在行或字符串末尾的 \n 之前。 | -\d{4}$ | "8-12-2012" 中的 "-2012" |
\a | 匹配必須出現在字符串的開頭。 | \a\w{4} | "code-007-" 中的 "code" |
\z | 匹配必須出現在字符串的末尾或出現在字符串末尾的 \n 之前。 | -\d{3}\z | "bond-901-007" 中的 "-007" |
\z | 匹配必須出現在字符串的末尾。 | -\d{3}\z | "-901-333" 中的 "-333" |
\g | 匹配必須出現在上一個匹配結束的地方。 | \g\(\d\) | "(1)(3)(5)[7](9)" 中的 "(1)"、 "(3)" 和 "(5)" |
\b | 匹配一個單詞邊界,也就是指單詞和空格間的位置。 | er\b | 匹配"never"中的"er",但不能匹配"verb"中的"er"。 |
\b | 匹配非單詞邊界。 | er\b | 匹配"verb"中的"er",但不能匹配"never"中的"er"。 |
4) 分組構造
分組構造描述了正則表達式的子表達式,通常用于捕獲輸入字符串的子字符串。
下表列出了分組構造:
分組構造 | 描述 | 模式 | 匹配 |
---|---|---|---|
( subexpression ) | 捕獲匹配的子表達式并將其分配到一個從零開始的序號中。 | (\w)\1 | "deep" 中的 "ee" |
(?< name >subexpression) | 將匹配的子表達式捕獲到一個命名組中。 | (?< double>\w)\k< double> | "deep" 中的 "ee" |
(?< name1 -name2 >subexpression) | 定義平衡組定義。 | (((?'open'\()[^\(\)]*)+((?'close-open'\))[^\(\)]*)+)*(?(open)(?!))$ | "3+2^((1-3)*(3-1))" 中的 "((1-3)*(3-1))" |
(?: subexpression) | 定義非捕獲組。 | write(?:line)? | "console.writeline()" 中的 "writeline" |
(?imnsx-imnsx:subexpression) | 應用或禁用 subexpression 中指定的選項。 | a\d{2}(?i:\w+)\b | "a12xl a12xl a12xl" 中的 "a12xl" 和 "a12xl" |
(?= subexpression) | 零寬度正預測先行斷言。 | \w+(?=\.) | "he is. the dog ran. the sun is out." 中的 "is"、 "ran" 和 "out" |
(?! subexpression) | 零寬度負預測先行斷言。 | \b(?!un)\w+\b | "unsure sure unity used" 中的 "sure" 和 "used" |
(?<=subexpression) | 零寬度正回顧后發斷言。 | (?<=19)\d{2}\b | "1851 1999 1950 1905 2003" 中的 "99"、"50"和 "05" |
(?<! subexpression) | 零寬度負回顧后發斷言。 | (?<!wo)man\b | "hi woman hi man" 中的 "man" |
(?> subexpression) | 非回溯(也稱為"貪婪")子表達式。 | [13579](?>a+b+) | "1abb 3abbc 5ab 5ac" 中的 "1abb"、 "3abb" 和 "5ab" |
using system; using system.text.regularexpressions; public class example { ? ?public static void main() ? ?{ ? ? ? string input = "1851 1999 1950 1905 2003"; ? ? ? string pattern = @"(?<=19)\d{2}\b"; ? ? ? foreach (match match in regex.matches(input, pattern)) ? ? ? ? ?console.writeline(match.value); ? ?} }
5) 限定符
限定符指定在輸入字符串中必須存在上一個元素(可以是字符、組或字符類)的多少個范例才能出現匹配項。 限定符包括下表中列出的語言元素。
下表列出了限定符:
限定符 | 描述 | 模式 | 匹配 |
---|---|---|---|
* | 匹配上一個元素零次或多次。 | \d*\.\d | ".0"、 "19.9"、 "219.9" |
+ | 匹配上一個元素一次或多次。 | "be+" | "been" 中的 "bee", "bent" 中的 "be" |
? | 匹配上一個元素零次或一次。 | "rai?n" | "ran"、 "rain" |
{ n } | 匹配上一個元素恰好 n 次。 | ",\d{3}" | "1,043.6" 中的 ",043", "9,876,543,210" 中的 ",876"、 ",543" 和 ",210" |
{ n ,} | 匹配上一個元素至少 n 次。 | "\d{2,}" | "166"、 "29"、 "1930" |
{ n , m } | 匹配上一個元素至少 n 次,但不多于 m 次。 | "\d{3,5}" | "166", "17668", "193024" 中的 "19302" |
*? | 匹配上一個元素零次或多次,但次數盡可能少。 | \d*?\.\d | ".0"、 "19.9"、 "219.9" |
+? | 匹配上一個元素一次或多次,但次數盡可能少。 | "be+?" | "been" 中的 "be", "bent" 中的 "be" |
?? | 匹配上一個元素零次或一次,但次數盡可能少。 | "rai??n" | "ran"、 "rain" |
{ n }? | 匹配前導元素恰好 n 次。 | ",\d{3}?" | "1,043.6" 中的 ",043", "9,876,543,210" 中的 ",876"、 ",543" 和 ",210" |
{ n ,}? | 匹配上一個元素至少 n 次,但次數盡可能少。 | "\d{2,}?" | "166"、 "29" 和 "1930" |
{ n , m }? | 匹配上一個元素的次數介于 n 和 m 之間,但次數盡可能少。 | "\d{3,5}?" | "166", "17668", "193024" 中的 "193" 和 "024" |
6) 反向引用構造
反向引用允許在同一正則表達式中隨后標識以前匹配的子表達式。
下表列出了反向引用構造:
反向引用構造 | 描述 | 模式 | 匹配 |
---|---|---|---|
\ number | 反向引用。 匹配編號子表達式的值。 | (\w)\1 | "seek" 中的 "ee" |
\k< name > | 命名反向引用。 匹配命名表達式的值。 | (?< char>\w)\k< char> | "seek" 中的 "ee" |
7) 備用構造
備用構造用于修改正則表達式以啟用 either/or 匹配。
下表列出了備用構造:
備用構造 | 描述 | 模式 | 匹配 |
---|---|---|---|
| | 匹配以豎線 (|) 字符分隔的任何一個元素。 | th(e|is|at) | "this is the day. " 中的 "the" 和 "this" |
(?( expression )yes | no ) | 如果正則表達式模式由 expression 匹配指定,則匹配 yes;否則匹配可選的 no 部分。 expression 被解釋為零寬度斷言。 | (?(a)a\d{2}\b|\b\d{3}\b) | "a10 c103 910" 中的 "a10" 和 "910" |
(?( name )yes | no ) | 如果 name 或已命名或已編號的捕獲組具有匹配,則匹配 yes;否則匹配可選的 no。 | (?< quoted>")?(?(quoted).+?"|\s+\s) | "dogs.jpg "yiska playing.jpg"" 中的 dogs.jpg 和 "yiska playing.jpg" |
8) 替換
替換是替換模式中使用的正則表達式。
下表列出了用于替換的字符:
字符 | 描述 | 模式 | 替換模式 | 輸入字符串 | 結果字符串 |
---|---|---|---|---|---|
$number | 替換按組 number 匹配的子字符串。 | \b(\w+)(\s)(\w+)\b | $3$2$1 | "one two" | "two one" |
${name} | 替換按命名組 name 匹配的子字符串。 | \b(?< word1>\w+)(\s)(?< word2>\w+)\b | ${word2} ${word1} | "one two" | "two one" |
$$ | 替換字符"$"。 | \b(\d+)\s?usd | 1 | "103 usd" | "$103" |
$& | 替換整個匹配項的一個副本。 | (\$*(\d*(\.+\d+)?){1}) | **$& | "$1.30" | "**$1.30**" |
$` | 替換匹配前的輸入字符串的所有文本。 | b+ | $` | "aabbcc" | "aaaacc" |
$' | 替換匹配后的輸入字符串的所有文本。 | b+ | $' | "aabbcc" | "aacccc" |
$+ | 替換最后捕獲的組。 | b+(c+) | $+ | "aabbccdd" | aaccdd |
$_ | 替換整個輸入字符串。 | b+ | $_ | "aabbcc" | "aaaabbcccc" |
9) 雜項構造
下表列出了各種雜項構造:
構造 | 描述 | 范例 |
---|---|---|
(?imnsx-imnsx) | 在模式中間對諸如不區分大小寫這樣的選項進行設置或禁用。 | \ba(?i)b\w+\b 匹配 "aba able act" 中的 "aba" 和 "able" |
(?#注釋) | 內聯注釋。該注釋在第一個右括號處終止。 | \ba(?#匹配以a開頭的單詞)\w+\b |
# [行尾] | 該注釋以非轉義的 # 開頭,并繼續到行的結尾。 | (?x)\ba\w+\b#匹配以 a 開頭的單詞 |
2. regex 類
regex 類用于表示一個正則表達式。
下表列出了 regex 類中一些常用的方法:
序號 | 方法 & 描述 |
---|---|
1 | public bool ismatch( string input ) 指示 regex 構造函數中指定的正則表達式是否在指定的輸入字符串中找到匹配項。 |
2 | public bool ismatch( string input, int startat ) 指示 regex 構造函數中指定的正則表達式是否在指定的輸入字符串中找到匹配項,從字符串中指定的開始位置開始。 |
3 | public static bool ismatch( string input, string pattern ) 指示指定的正則表達式是否在指定的輸入字符串中找到匹配項。 |
4 | public matchcollection matches( string input ) 在指定的輸入字符串中搜索正則表達式的所有匹配項。 |
5 | public string replace( string input, string replacement ) 在指定的輸入字符串中,把所有匹配正則表達式模式的所有匹配的字符串替換為指定的替換字符串。 |
6 | public string[] split( string input ) 把輸入字符串分割為子字符串數組,根據在 regex 構造函數中指定的正則表達式模式定義的位置進行分割。 |
如需了解 regex 類的完整的屬性列表,請參閱微軟的 c# 文檔。
范例 1:
下面的范例匹配了以 's' 開頭的單詞:
using system; using system.text.regularexpressions; namespace regexapplication { ? ?class program ? ?{ ? ? ? private static void showmatch(string text, string expr) ? ? ? { ? ? ? ? ?console.writeline("the expression: " + expr); ? ? ? ? ?matchcollection mc = regex.matches(text, expr); ? ? ? ? ?foreach (match m in mc) ? ? ? ? ?{ ? ? ? ? ? ? console.writeline(m); ? ? ? ? ?} ? ? ? } ? ? ? static void main(string[] args) ? ? ? { ? ? ? ? ?string str = "a thousand splendid suns"; ? ? ? ? ?console.writeline("matching words that start with 's': "); ? ? ? ? ?showmatch(str, @"\bs\s*"); ? ? ? ? ?console.readkey(); ? ? ? } ? ?} }
當上面的代碼被編譯和執行時,它會產生下列結果:
matching words that start with 's': the expression: \bs\s* splendid suns
范例 2:
下面的范例匹配了以 'm' 開頭以 'e' 結尾的單詞:
using system; using system.text.regularexpressions; namespace regexapplication { ? ?class program ? ?{ ? ? ? private static void showmatch(string text, string expr) ? ? ? { ? ? ? ? ?console.writeline("the expression: " + expr); ? ? ? ? ?matchcollection mc = regex.matches(text, expr); ? ? ? ? ?foreach (match m in mc) ? ? ? ? ?{ ? ? ? ? ? ? console.writeline(m); ? ? ? ? ?} ? ? ? } ? ? ? static void main(string[] args) ? ? ? { ? ? ? ? ?string str = "make maze and manage to measure it"; ? ? ? ? ?console.writeline("matching words start with 'm' and ends with 'e':"); ? ? ? ? ?showmatch(str, @"\bm\s*e\b"); ? ? ? ? ?console.readkey(); ? ? ? } ? ?} }
當上面的代碼被編譯和執行時,它會產生下列結果:
matching words start with 'm' and ends with 'e': the expression: \bm\s*e\b make maze manage measure
范例 3:
下面的范例替換掉多余的空格:
using system; using system.text.regularexpressions; namespace regexapplication { ? ?class program ? ?{ ? ? ? static void main(string[] args) ? ? ? { ? ? ? ? ?string input = "hello ? world ? "; ? ? ? ? ?string pattern = "\\s+"; ? ? ? ? ?string replacement = " "; ? ? ? ? ?regex rgx = new regex(pattern); ? ? ? ? ?string result = rgx.replace(input, replacement); ? ? ? ? ?console.writeline("original string: {0}", input); ? ? ? ? ?console.writeline("replacement string: {0}", result); ? ? ? ? ? ? ?console.readkey(); ? ? ? } ? ?} }
當上面的代碼被編譯和執行時,它會產生下列結果:
original string: hello world replacement string: hello world