(转载)正则表达式快速入门。

8 心灵亮光 1年前 322次点击

正则表达式本身就是一种编程语言,用于操作文本并针对文本操作进行了优化,这是使用字面字符和元字符(metacharacter)实现的。字面字符指的是目标字符串必须与之匹配的字符,而元字符正则表达式分析器如何行动。表达式分析器负责解释正则表达式并将其应用于目标字符串。这些元字符赋予了正则表达式灵活性和强大的处理功能。

1 C#中的正则表达式类

在.NET Framework中,正则表达式是通过命名空间 System.Text.RegularExpression中的几个类实现的,这些类让您能够分析和应用正则表达式以及使用捕获组。

Regex类

Regex类提供了正则表达式分析器和引擎的实现,它将正则表达式应用于输入字符串。通过使用这个类,可以快速分析大量文本,看其是否符合特定模式,还可轻松地提取和编辑子串。

Regex 类提供了实例成员和静态成员,让您能够以两种不同的方式使用它。当您创建Regex 类的实例时,不会编译和缓存表达式模式;但是当您使用静态方法时,将编译和缓存表达式模式。默认情况下,正则表达式引擎将缓存最近使用的15个静态正则表达式。如果需要大量使用一组固定的正则表达式,就应使用静态方法,而不是相应的实例方法。

Match和MatchCollection类

使用Regex类的Match方法将正则表达式应用于字符串时,将用Match类的实例表示第一个匹配项。MatchCollection包含一组Match实例,这些Match是通过重复应用正则表达式找到的匹配项。

Group和Capture类

Match.Groups属性表示单个匹配项中所有的捕获组。每个捕获组都是一个Group实例,而Group实例包含一组Capture对象,这些对象可通过Captures属性获取。Capture表示单个子表达式匹配返回的结果。

2 使用正则表达式验证字符串

正则表达式的一种常见用途是验证字符串:检查它是否符合特定模式。为此,可使用方法IsMatch的重载版本之一。

3 使用正则表达式搜索子串

正则表达式还可用于搜索与特定正则表达式模式匹配的子串。这种搜索可执行一次,也可重复执行。在前一种情况下,将返回第一个匹配项;在后一种情况下,将返回一系列匹配项。

要以这种方式搜索子串,可使用方法Match或Matches。其中,前者返回第一个匹配项,而后者返回一系列不重叠的匹配项。

正则表达式快速入门

正则表达式是对字串操作的一种逻辑公式,就是用事先定义好的一些特定字元、及这些特定字元的组合,组成一个“规则字串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。

表达式由一些普通字元和一些元字元 (metacharacters)组成。普通字元包括大小写的字母和数字,而元字元则具有特殊的含义,我们下面会给予解释。

在最简单的情况下,一个正则表达式看上去就是一个普通的查找串。例如,正则表达式"testing"中没有包含任何元字元,它可以匹配"testing"和"testing123"等字串,但是不能匹配"Testing"。

要想真正的用好正则表达式,正确的理解元字元是最重要的事情。下表列出了所有的元字元和对它们的一个简短的描述。

元字    描述

\ 将下一个字元标记符、或一个向後引用、或一个八进制转义符。例如,“\\n”匹配\n。“\n”匹配分行符号。序列“\\”匹配“\”而“\(”则匹配“(”。即相当於多种程式设计语言中都有的“转义字元”的概念。

^ 匹配输入字行首。如果设置了RegExp物件的Multiline属性,^也匹配“\n”或“\r”之後的位置。

$ 匹配输入行尾。如果设置了RegExp物件的Multiline属性,$也匹配“\n”或“\r”之前的位置。

* 匹配前面的子运算式任意次。例如,zo*能匹配“z”,也能匹配“zo”以及“zoo”。*等价於{0,}。

+ 匹配前面的子运算式一次或多次(大於等於1次)。例如,“zo+”能匹配“zo”以及“zoo”,但不能匹配“z”。+等价於{1,}。

? 匹配前面的子运算式零次或一次。例如,“do(es)?”可以匹配“do”或“does”。?等价於{0,1}。

{n} n是一个非负整数。匹配确定的n次。例如,“o{2}”不能匹配“Bob”中的“o”,但是能匹配“food”中的两个o。

{n,}

n是一个非负整数。至少匹配n 次。例如,“o{2,}”不能匹配“Bob”中的“o”,但能匹配“foooood”中的所有o。“o{1,}”等价於“o+”。“o{0,}”则等价於“o*”。

{n,m}

m和n均为非负整数,其中n<=m。最少匹配n次且最多匹配m 次。例如,“o{1,3}”将匹配“fooooood”中的前三个o为一组,後三个o为一组。“o{0,1}”等价於“o?”。请注意在逗号和两个数之间不能有空格。

? 当该字元紧跟在任何一个其他限制符(*,+,?,{n},{n,},{n,m })後面时,匹配模式是非贪婪的。非贪婪模式尽可能少地匹配所搜索的字串,而预设的贪婪模式则尽可能多地匹配所搜索的字串。例如,对於字串“oooo”,“o+”将尽可能多地匹配“o”,得到结果[“oooo”],而“o+?”将尽可能少地匹配“o”,得到结果 ['o', 'o', 'o', 'o']

.点 匹配除“\n”和"\r"之外的任何单个字元。要匹配包括“\n”和"\r"在内的任何字元,请使用像“[\s\S]”的模式。

(pattern)

匹配pattern并获取这一匹配。所获取的匹配可以从产生的Matches集合得到,在VBScript中使用SubMatches集合,在JScript中则使用$0…$9属性。要匹配圆括号字元,请使用“\(”或“\)”。

(?:pattern)

非获取匹配,匹配pattern但不获取匹配结果,不进行存储供以後使用。这在使用或字元“(|)”来组合一个模式的各个部分时很有用。例如“industr(?:y|ies)”就是一个比“industry|industries”更简略的运算式。

(?=pattern)

非获取匹配,正向肯定预查,在任何匹配pattern的字串开始处匹配查找字串,该匹配不需要获取供以後使用。例如,“Windows(?=95|98|NT|2000)”能匹配“Windows2000”中的“Windows”,但不能匹配“Windows3.1”中的“Windows”。预查不消耗字元,也就是说,在一个匹配发生後,在最後一次匹配之後立即开始下一次匹配的搜索,而不是从包含预查的字元之後开始。

(?!pattern)

非获取匹配,正向否定预查,在任何不匹配pattern的字串开始处匹配查找字串,该匹配不需要获取供以後使用。例如“Windows(?!95|98|NT|2000)”能匹配“Windows3.1”中的“Windows”,但不能匹配“Windows2000”中的“Windows”。

(?<=pattern)

非获取匹配,反向肯定预查,与正向肯定预查类似,只是方向相反。例如,“(?<=95|98|NT|2000)Windows”能匹配“2000Windows”中的“Windows”,但不能匹配“3.1Windows”中的“Windows”。

*python的正则表达式没有完全按照正则表达式规范实现,所以一些高级特性建议使用其他语言如java、scala等

(?

非获取匹配,反向否定预查,与正向否定预查类似,只是方向相反。例如“(?

*python的正则表达式没有完全按照正则表达式规范实现,所以一些高级特性建议使用其他语言如java、scala等

x|y 匹配x或y。例如,“z|food”能匹配“z”或“food”(此处请谨慎)。“[z|f]ood”则匹配“zood”或“food”。

[xyz] 字元集合。匹配所包含的任意一个字元。例如,“[abc]”可以匹配“plain”中的“a”。

[^xyz] 负值字元集合。匹配未包含的任意字元。例如,“[^abc]”可以匹配“plain”中的“plin”任一字元。

[a-z]

字元范围。匹配指定范围内的任意字元。例如,“[a-z]”可以匹配“a”到“z”范围内的任意小写字母字元。

注意:只有连字号在字元组内部时,并且出现在两个字元之间时,才能表示字元的范围; 如果出字元组的开头,则只能表示连字号本身.

[^a-z] 负值字元范围。匹配任何不在指定范围内的任意字元。例如,“[^a-z]”可以匹配任何不在“a”到“z”范围内的任意字元。

\b

匹配一个单词的边界,也就是指单词和空格间的位置(即正则表达式的“匹配”有两种概念,一种是匹配字元,一种是匹配位置,这里的\b就是匹配位置的)。例如,“er\b”可以匹配“never”中的“er”,但不能匹配“verb”中的“er”;“\b1_”可以匹配“1_23”中的“1_”,但不能匹配“21_3”中的“1_”。

\B 匹配非单词边界。“er\B”能匹配“verb”中的“er”,但不能匹配“never”中的“er”。

\cx 匹配由x指明的控制字元。例如,\cM匹配一个Control-M或回车符。x的值必须为A-Z或a-z之一。否则,将c视为一个原义的“c”字元。

\d 匹配一个数字字元。等价於[0-9]。grep 要加上-P,perl正则支持

\D 匹配一个非数字字元。等价於[^0-9]。grep要加上-P,perl正则支持

\f 匹配一个换页符。等价於\x0c和\cL。

\n 匹配一个分行符号。等价於\x0a和\cJ。

\r 匹配一个回车符。等价於\x0d和\cM。

\s 匹配任何不可见字元,包括空格、定位字元、换页符等等。等价於[ \f\n\r\t\v]。

\S 匹配任何可见字元。等价於[^ \f\n\r\t\v]。

\t 匹配一个定位字元。等价於\x09和\cI。

\v 匹配一个垂直定位字元。等价於\x0b和\cK。

\w 匹配包括底线的任何单词字元。类似但不等价於“[A-Za-z0-9_]”,这里的"单词"字元使用Unicode字元集。

\W 匹配任何非单词字元。等价於“[^A-Za-z0-9_]”。

\xn 匹配n,其中n 为十六进位转义值。十六进位转义值必须为确定的两个数字长。例如,“\x41”匹配“A”。“\x041”则等价於“\x04&1”。正则表达式中可以使用ASCII编码。

\num 匹配num,其中num是一个正整数。对所获取的匹配的引用。例如,“(.)\1”匹配两个连续的相同字元。

\n 标识一个八进制转义值或一个向後引用。如果\n之前至少n个获取的子运算式,则n为向後引用。否则,如果n 为八进位数字(0-7),则n为一个八进制转义值。

\nm 标识一个八进制转义值或一个向後引用。如果\nm之前至少有nm个获得子运算式,则nm为向後引用。如果\nm之前至少有n个获取,则n为一个後跟文字m的向後引用。如果前面的条件都不满足,若n和m均为八进位数字(0-7),则\nm 将匹配八进制转义值

nm。

\nml 如果n为八进位数字(0-7),且m和l均为八进位数字(0-7),则匹配八进制转义值nml。

\un 匹配n,其中n是一个用四个十六进位数字表示的Unicode字元。例如,\u00A9匹配版权符号(©)。

\p{P}

小写 p 是 property 的意思,表示 Unicode 属性,用於 Unicode 正运算式的首码。中括弧内的“P”表示Unicode 字元集七个字元属性之一:标点字元。

其他六个属性:

L:字母;

M:标记符号(一般不会单独出现);

Z:分隔符号(比如空格、换行等);

S:符号(比如数学符号、货币符号等);

N:数字(比如阿拉伯数字、罗马数字等);

共 1 条评论
心灵亮光 [楼主] 1年前
0 

C:其他字元。

*注:此语法部分语言不支援,例:javascript。

\<

\>

匹配词(word)的开始(\<)和结束(\>)。例如正则表达式\能够匹配字串"for the wise"中的"the",但是不能匹配字串"otherwise"中的"the"。注意:这个元字元不是所有的软体都支援的。

( )

将( 和 ) 之间的运算式定义为“组”(group),并且将匹配这个运算式的字元保存到一个临时区域(一个正则表达式中最多可以保存9个),它们可以用 \1 到\9 的符号来引用。

| 将两个匹配条件进行逻辑“或”(or)运算。例如正则表达式(him|her) 匹配"it belongs to him"和"it belongs to her",但是不能匹配"it belongs to them."。注意:这个元字元不是所有的软体都支援的。

最简单的元字元是点,它能够匹配任何单个字元(注意不包括分行符号)。假定有个文件test.txt包含以下几行内容:

he is arat

he is in a rut

the food is Rotten

I like root beer

我们可以使用grep命令来测试我们的正则表达式,grep命令使用正则表达式 去尝试匹配指定档的每一行,并将至少有一处匹配运算式的所有行显示出来。命令

grep r.t test.txt

在test.txt文件中的每一行中搜索正则表达式r.t,并列印输出匹配的行。正则表达式r.t匹配一个r接着任何一个字元再接着一个t。所以它将匹配档中的rat和rut,而不能匹配Rotten中的Rot,因为正则表达式是大小写敏感的。要想同时匹配大写和小写字母,应该使用

字元区间元字元 (方括号)。正则表达式[Rr]能够同时匹配R和r。所以,要想匹配一个大写或者小写的r接着任何一个字元再接着一个t就要使用这个运算式:[Rr].t。

要想匹配行首的字元要使用抑扬字元(^)——有时也被叫做插入符。例如,想找到text.txt中行首"he"打头的行,您可能会先用简单运算式he,但是这会匹配第三行的the,所以要

使用正则表达式^he,它只匹配在行首出现的he。

有时候指定“除了×××都匹配”会比较容易达到目的,当抑扬字元(^)出方括号中时,它表示“排除”,例如要匹配he ,但是排除前面是t or s的情形(也就是the和she),可以使用:[^st]he。

可以使用方括号来指定多个字元区间。例如正则表达式[A-Za-z]匹配任何字母,包括大写和小写的;正则表达式[A-Za-z][A-Za-z]* 匹配一个字母後面接着0或者多个字母(大写或者小写)。当然我们也可以用

元字元 +做到同样的事情,也就是:[A-Za-z]+ ,和[A-Za-z][A-Za-z]*完全等价。但是要注意元字元+ 并不是所有支援正则表达式的程式都支援的。关於这一点可以参考後面的正则表达式语法支援情况。

要指定特定数量的匹配,要使用大括弧(注意并不是所有扩展正则表达式的实现都支持大括弧。此外,根据具体的实现,您可能需要先使用反斜线对其进行转义。)。想匹配所有10和100的实例而排除1和 1000,可以使用:10\{1,2\} 或 10{1, 2},这个正则表达式匹配数字1後面跟着1或者2个0的模式。在这个元字元的使用中一个有用的变化是忽略第二个数字,例如正则表达式0\{3,\} 或 0{3,} 将匹配至少3个连续的0。

例1

将所有方法foo(a,b,c)的实例改为foo(b,a,c)。这里a、b和c可以是任何提供给方法foo()的参数。也就是说我们要实现这样的转换:

之前 之後

foo(10,7,2) foo(7,10,2)

foo(x+13,y-2,10) foo(y-2,x+13,10)

foo( bar(8), x+y+z, 5) foo( x+y+z, bar(8), 5)

下面这条替换命令能够实现这一方法:

:%s/foo\(([^,]*),([^,]*),([^,]*)\)/foo\(\2,\1,\3\)/g

让我们把它打散来加以分析。写出这个运算式的基本思路是找出foo()和它的括弧中的三个参数的位置。第一个参数是用这个运算式来识别的::([^,]*),我们可以从里向外来分析它:

[^,] 除了逗号之外的任何字元

[^,]* 0或者多个非逗号字元

([^,]*) 将这些非逗号字元标记为\1,这样可以在之後的替换模式运算式中引用它

([^,]*), 我们必须找到0或者多个非逗号字元後面跟着一个逗号,并且非逗号字元那部分要标记出来以备後用。

正是指出一个使用正则表达式 常见错误的最佳时机。为什麽我们要使用[^,]*这样的一个运算式,而不是更加简单直接的写法,例如:.*,来匹配第一个参数呢?设想我们使用模式.*来匹配字串"10,7,2",它应该匹配"10,"还是"10,7,"?为了解决这个两义性(ambiguity),正则表达式规定一律按照最长的串来,在上面的例子中就是"10,7,",显然这样就找出了两个参数而不是我们期望的一个。所以,我们要使用[^,]*来强制取出第一个逗号之前的部分。

这个运算式我们已经分析到了:foo\(([^,]*),这一段可以简单的翻译为“当您找到foo(就把其後直到第一个逗号之前的部分标记为\1”。然後我们使用同样的办法标记第二个参数为\2。对第三个参数的标记方法也是一样,只是我们要搜索所有的字元直到右括弧。我们并没有必要去搜索第三个参数,因为我们不需要调整它的位置,但是这样的模式能够保证我们只去替换那些有三个参数的foo()方法调用,在foo()是一个

重载 (overloading)方法时这种明确的模式往往是比较保险的。然後,在替换部分,我们找到foo()的对应实例,然後利用标记好的部分进行替换,是把第一和第二个参数交换位置。

添加一条新评论

登录后可以发表评论 去登录