正则表达式语言标识字符模式。支持正则表达式的.NET类型基于Perl5正则表达式,同时支持搜索和搜索/替换功能。
正则表达式用于以下任务:
验证文本输入,例如密码和电话号码
将文本数据分析为更结构化的形式(例如,NuGet版本字符串)
替换文档中的文本模式(例如,仅整个单词)
本章分为两个概念部分,介绍.NET中正则表达式的基础知识,以及介绍正则表达式的参考部分。
所有正则表达式类型都在中定义。
注意本章中的示例都预加载到LINQPad中,其中还包括一个交互式正则表达式工具(按Ctrl+Shift+F1)。在线工具可在获得。
正则表达式基础知识最常见的正则表达式运算符之一是。?是与前面的项目0或1时间匹配的量词。换句话说,?表示。项目可以是单个字符,也可以是方括号中的复杂字符结构。例如,正则表达式“colou?r”匹配颜色和,但不匹配colouur:
(("color",@"colou?r").Success);//(("colour",@"colou?r").Success);//(("colouur",@"colou?r").Success);//False在较大的字符串中进行搜索。它返回的对象具有匹配项的索引和长度以及匹配的实际值的属性:
Matchm=("anycolouryoulike",@"colou?r");();//();//4();//6();//(());//colour你可以把看作是字符串的IndexOf方法的一个更强大的版本。不同之处在于它搜索而不是文字字符串。
方法是一个快捷方式,用于调用Match,然后测试Success属性。
默认情况下,正则表达式引擎从左到右工作,因此仅返回最左侧的匹配项。可以使用NextMatch方法返回更多匹配项:
Matchm1=("Onecolor?Therearetwocoloursinmyhead!",@"colou?rs?");Matchm2=();(m1);//(m2);//colours方法返回数组中的所有匹配项。我们可以重写前面的示例,如下所示:
foreach(("Onecolor?Therearetwocoloursinmyhead!",@"colou?rs?"))(m);另一个常见的正则表达式运算符是,用竖线|表示。交流发电机表示替代方案。以下匹配“Jen”、“Jenny”和“Jennifer”:
(("Jenny","Jen(ny|nifer)?"));//True交流发电机周围的括号将备选方案与表达式的其余部分分开。
注意您可以在匹配正则表达式时指定超时。如果匹配操作花费的时间超过指定的TimeSpan,则会抛出RegexMatchTimeoutException。如果程序处理任意正则表达式(例如,在高级搜索对话框中),这会很有用,因为它可以防止格式错误的正则表达式无限旋转。
编译的正则表达式在前面的一些示例中,我们使用相同的模式重复调用静态RegEx方法。在这些情况下,另一种方法是使用模式和实例化Regex对象,然后调用实例:
Regexr=newRegex(@"sausages?",);(("sausage"));//(("sausages"));//sausages指示RegEx实例使用轻量级代码生成(中的DynamicMethod)来动态构建和编译针对该特定正则表达式定制的代码。这样可以加快匹配速度,但会降低初始编译成本。
您还可以实例化Regex对象,而无需使用。正则表达式实例是不可变的。
注意正则表达式引擎速度很快。即使没有编译,简单的匹配通常也不到一微秒。
正则表达式选项正则表达式选项标志枚举允许您调整匹配行为。RegexOptions的常见用途是执行不区分大小写的搜索:
(("a","A",));//a这将应用当前区域性的大小写等效规则。使用“区域性不变”标志可以请求固定区域性,改为:
(("a","A",|));您可以使用单字母代码激活正则表达式本身中的大多数RegexOptions标志,如下所示:
(("a",@"(?i)A"));//a您可以在整个表达式中打开和关闭选项:
(("AAAa",@"(?i)a(?-i)a"));//Aa另一个有用的选项是IgnorePatternWhitespace或(?x)。这允许您插入空格以使正则表达式更具可读性,而无需按字面意思获取空格。
列出了所有RegExOptions值及其单字母代码。
正则表达式选项
枚举值
正则表达式代码
描述
没有
忽略案例
我
忽略大小写(默认情况下,正则表达式区分大小写)
多行
m
更改^和$,以便它们匹配行的开头/结尾,而不是字符串的开头/结尾
显式捕获
n
仅捕获显式命名或显式编号的组(请参阅)
编译
强制编译到IL(请参阅)
单线
s
使。匹配每个字符(而不是匹配除\n之外的每个字符)
忽略模式空白
x
从模式中消除未转义的空格
从右到左
r
从右到左搜索;无法在中游指定
ECMAScript
强制符合ECMA标准(默认情况下,实现不符合ECMA标准)
文化不变
关闭字符串比较的区域性特定行为
角色转义正则表达式具有以下元字符,这些元字符具有特殊含义而不是字面含义:
\*+?|{[()^$.@文本表示。这是为了绕过C34;));//F
当您指定或在表达式中包含(?m)时:
^匹配字符串或的开头(紧跟在\n之后)。
$匹配字符串或的末尾(紧邻\n之前)。
在多行模式下使用$有一个问题:Windows中的新行几乎总是用\r\n表示,而不仅仅是\n。这意味着要使$对Windows文件有用,您通常还必须匹配\r,并具有:
(?=\r?$)
可确保\r不会成为结果的一部分。以下匹配以“.txt”结尾的行:
stringfileNames=""+"\r\n"+""+"\r\n"+"";stringr=@".+\.txt(?=\r?$)";foreach((fileNames,r,))(m+"");OUTPUT:
以下内容匹配字符串s中的所有空行:
MatchCollectionemptyLines=(s,"^(?=\r?$)",);
以下内容匹配所有空行或仅包含空格的行:
MatchCollectionblankLines=(s,"^[\t]*(?=\r?$)",);注意
由于锚点匹配位置而不是字符,因此指定锚点本身与空字符串匹配:
(("x","代码:(("5islessthan10",@"\d+",m=(()*10).ToString()));OUTPUT:50islessthan100在中,我们展示了如何使用MatchEvaluator为HTML适当地转义Unicode字符。
拆分文本静态方法是字符串的更强大的版本。拆分方法,正则表达式表示分隔符模式。在这个例子中,我们拆分一个字符串,其中任何数字都算作分隔符:
foreach(("a5b7c",@"\d"))(s+"");//abc此处的结果不包括分隔符本身。但是,您可以通过将表达式包装在中来包含分隔符。下面将驼峰大小写字符串拆分为单独的单词:
foreach(("oneTwoThree",@"(?=[A-Z])"))(s+"");//oneTwoThree说明书正则表达式食谱匹配美国社会安全号码/电话号码stringssNum=@"\d{3}-\d{2}-\d{4}";(("123-45-6789",ssNum));//Truestringphone=@"(?x)(\d{3}[-\s]|\(\d{3}\)\s?)\d{3}[-\s]?\d{4}";(("",phone));//(("(123)456-7890",phone));//True
提取“名称=值”对(每行一个)请注意,这以指令(?m)开头:
stringr=@"(?m)^\s*(?'name'\w+)\s*=\s*(?'value'.*)\s*(?=\r?$)";stringtext=@"id=3secure=truetimeout=30";foreach((text,r))(["name"]+"is"+["value"]);idis3secureistruetimeoutis30
强密码验证下面检查密码是否至少包含六个字符,以及密码是否包含数字、符号或标点符号:
stringr=@"(?x)^(?=.*(\d|\p{P}|\p{S})).{6,}";(("abc12",r));//(("abcdef",r));//(("ab88yz",r));//True至少80个字符的行stringr=@"(?m)^.{80,}(?=\r?$)";stringfifty=newstring('x',50);stringeighty=newstring('x',80);stringtext=eighty+"\r\n"+fifty+"\r\n"+eighty;((text,r).Count);//2
解析日期/时间(N/N/NH:M:SAM/PM)此表达式处理各种数字日期格式,无论年份排在第一位还是最后一年,该表达式都有效。(?x)指令通过允许空格来提高可读性;(?i)关闭区分大小写(对于可选的AM/PM指示符)。然后,您可以通过组集合访问比赛的每个组件:
stringr=@"(?x)(?i)(\d{1,4})[./-](\d{1,2})[./-](\d{1,4})[\sT](\d+):(\d+):(\d+)\s?(A\.?M\.?|P\.?M\.?)?";stringtext="01/02/20085:20:50PM";foreach((text,r).Groups)(+"");01/02/20085:20:50PM0102200852050PM(当然,这不会验证日期/时间是否正确。
匹配的罗马数字stringr=@"(?i)\bm*"+@"(d?c{0,3}|c[dm])"+@"(l?x{0,3}|x[lc])"+@"(v?i{0,3}|i[vx])"+@"\b";(("MCMLXXXIV",r));//True
删除重复的单词在这里,我们捕获一个名为dupe的命名组:
stringr=@"(?'dupe'\w+)\W\k'dupe'";stringtext="Inthethebeginning";((text,r,"${dupe}"));Inthebeginning字数stringr=@"\b(\w|[-'])+\b";stringtext="It'sallmumbo-jumbotome";((text,r).Count);//5
匹配GUIDstringr=@"(?i)\b"+@"[0-9a-fA-F]{8}\-"+@"[0-9a-fA-F]{4}\-"+@"[0-9a-fA-F]{4}\-"+@"[0-9a-fA-F]{4}\-"+@"[0-9a-fA-F]{12}"+@"\b";stringtext="Itskeyis{3F2504E0-4F89-11D3-9A0C-0305E82C3301}.";((text,r).Index);//12
解析XML/HTML标记正则表达式对于解析HTML片段很有用,尤其是当文档的格式可能不完美时:
stringr=@"(?'tag'\w+?).*"+//lazy-matchfirsttag,andnameit'tag'@"(?'text'.*?)"+//lazy-matchtextcontent,nameit'textd'@"/\k'tag'";//matchlasttag,denotedby'tag'stringtext="h1hello/h1";Matchm=(text,r);(["tag"]);//(["text"]);//hello
拆分驼峰大小写的单词这需要以包含大写分隔符:
stringr=@"(?=[A-Z])";foreach(("oneTwoThree",r))(s+"");//oneTwoThree获取合法文件名stringinput="My\"good\"";char[]invalidChars=();stringinvalidString=(newstring(invalidChars));stringvalid=(input,"["+invalidString+"]","");(valid);
转义HTML的Unicode字符stringhtmlFragment="©2007";stringresult=(htmlFragment,@"[\u0080-\uFFFF]",m=@""+((int)[0]).ToString()+";");(result);//©2007
HTTP查询字符串中的取消转义字符stringsample="C%23rocks";stringresult=(sample,@"%[0-9a-f][0-9a-f]",m=((char)((1),16)).ToString(),);(result);//Ccomment)
内联注释
#comment
注释到行尾(仅适用于忽略模式空白模式)
正则表达式选项
选择
意义
(?一)
不区分大小写的匹配(“忽略”大小写)
(?m)
多线模式;更改^和$,以便它们匹配任何行的开头和结尾
(?n)
仅捕获显式命名或编号的组
(?
编译为中间语言
(?
单线模式;更改“.”的含义,使其与每个字符匹配
(?x)
从模式中消除未转义的空格
(?r)
从右到左搜索;无法在中游指定