正则表达式简易讲义

来源:互联网 发布:软件项目质量管理计划 编辑:程序博客网 时间:2024/05/20 11:26

正则表达式(1) - 定义

正则表达式(regular expression)描述了一种字符串匹配的模式,可以用来检查一个串是否含有某种子串、将匹配的子串做替换或者从某个串中取出符合某个条件的子串等。

  • 列目录时, dir *.txt或ls *.txt中的*.txt就不是一个正则表达式,因为这里*与正则式的*的含义是不同的。
  • 构造正则表达式的方法和创建数学表达式的方法一样。也就是用多种元字符与运算符可以将小的表达式结合在一起来创建更大的表达式。正则表达式的组件可以是单个的字符、字符集合、字符范围、字符间的选择或者所有这些组件的任意组合。

正则表达式是由普通字符(例如字符 a 到 z)以及特殊字符(称为"元字符")组成的文字模式。模式描述在搜索文本时要匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。

正则表达式(2) - 元字符

1.元字符列表

下表包含了元字符的完整列表以及它们在正则表达式上下文中的行为:

字符描述\将下一个字符标记为一个特殊字符、或一个原义字符、或一个 向后引用、或一个八进制转义符。例如,'n' 匹配字符 "n"。'\n' 匹配一个换行符。序列 '\\' 匹配 "\" 而 "\(" 则匹配 "("。^匹配输入字符串的开始位置。如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配 '\n' 或 '\r' 之后的位置。$匹配输入字符串的结束位置。如果设置了RegExp 对象的 Multiline 属性,$ 也匹配 '\n' 或 '\r' 之前的位置。*匹配前面的子表达式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。* 等价于{0,}。+匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,}。?匹配前面的子表达式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does" 中的"do" 。? 等价于 {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{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格。?当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 "oooo",'o+?' 将匹配单个 "o",而 'o+' 将匹配所有 'o'。.匹配除 "\n" 之外的任何单个字符。要匹配包括 '\n' 在内的任何字符,请使用象 '[.\n]' 的模式。(pattern)匹配 pattern 并获取这一匹配。所获取的匹配可以从产生的 Matches 集合得到,在VBScript 中使用 SubMatches 集合,在JScript 中则使用 $0…$9 属性。要匹配圆括号字符,请使用 '\(' 或 '\)'。(?:pattern)匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用 "或" 字符 (|) 来组合一个模式的各个部分是很有用。例如, 'industr(?:y|ies) 就是一个比 'industry|industries' 更简略的表达式。(?=pattern)正向预查,在任何匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,'Windows (?=95|98|NT|2000)' 能匹配 "Windows 2000" 中的 "Windows" ,但不能匹配 "Windows 3.1" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。(?!pattern)负向预查,在任何不匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如'Windows (?!95|98|NT|2000)' 能匹配 "Windows 3.1" 中的 "Windows",但不能匹配 "Windows 2000" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。x|y匹配 x 或 y。例如,'z|food' 能匹配 "z" 或 "food"。'(z|f)ood' 则匹配 "zood" 或 "food"。[xyz]字符集合。匹配所包含的任意一个字符。例如, '[abc]' 可以匹配 "plain" 中的 'a'。[^xyz]负值字符集合。匹配未包含的任意字符。例如, '[^abc]' 可以匹配 "plain" 中的'p'、'l'、'i'、'n'。[a-z]字符范围。匹配指定范围内的任意字符。例如,'[a-z]' 可以匹配 'a' 到 'z' 范围内的任意小写字母字符。[^a-z]负值字符范围。匹配任何不在指定范围内的任意字符。例如,'[^a-z]' 可以匹配任何不在 'a' 到 'z' 范围内的任意字符。\b匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。\B匹配非单词边界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。\cx匹配由 x 指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 'c' 字符。\d匹配一个数字字符。等价于 [0-9]。\D匹配一个非数字字符。等价于 [^0-9]。\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_]'。\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-3),且 m 和 l 均为八进制数字 (0-7),则匹配八进制转义值 nml。\un匹配 n,其中 n 是一个用四个十六进制数字表示的 Unicode 字符。例如, \u00A9 匹配版权符号 (?)。

正则表达式括号的作用
1、限制多选项的范围 (Fri|1)st 这样写会匹配Frist或1st 如果去掉,则 Fri|1st就是匹配 Fri或1st
2、将若干个字符进行组合,受量词的同时作用。例如 th+ 表示匹配 th thh thhh(h无数次),如果是(th)+,则匹配的是th thth ththth(th无数次)
3、反向引用,即前面括号匹配到的东西记忆与后面,常用于匹配重复单词。
4、分组

常用元字符
代码           说明
.             匹配除换行符以外的任意字符
\w             匹配字母或数字或下划线或汉字
\s             匹配任意的空白符
\d             匹配数字
\b             匹配单词的开始或结束
^             匹配行的开始
$             匹配行的结束

常用反义元字符
代码   说明
\W       匹配任意不是字母,数字,下划线,汉字的字符
\S        匹配任意不是空白符的字符
\D      匹配任意非数字的字符
\B        匹配不是单词开头或结束的位置
[^x]       匹配除了x以外的任意字符
[^aeiou]   匹配除了aeiou这几个字母以外的任意字符


常用重复限定符
代码       说明
*         重复零次或更多次
+         重复一次或更多次
?         重复零次或一次
{n}       重复n次
{n,}        重复n次或更多次
{n,m}       重复n到m次

2.元字符说明

 一、最易理解的元字符。

  脱字符  ^   :表示匹配行首的文本

    美元符  $ :表示匹配行尾的文本

  例如:

^cat    //匹配以c作为一行的第一个字符是c,然后是一个a,紧接着一个t的文本

  以上正则表达式匹配的是:

  例如一个行  catdogcat  上面正则表达式匹配第一个cat。

  特殊正则说明:

^cat$    //匹配行开头是cat,然后就是行末尾的cat,说白了就是一行中仅仅只包含cat的行,没有其他字符。^$        //匹配行开头,然后就是行末尾了,说白了就是匹配一个空行(没有任何字符,也没有空白字符)^          //匹配行的开头,每一行都匹配

  下面用C#说明:

复制代码
        static void Main(string[] args)        {            Regex reg = new Regex("^cat");            reg.Match("catdog");            Console.WriteLine(reg.Match("catdog"));     //输出 cat            Console.WriteLine(reg.Match("dogcat"));     //输出 空白(啥都不输出)            Regex reg2 = new Regex("cat$");            Console.WriteLine(reg2.Match("catdog"));      //输出 空白(啥都不输出)            Console.WriteLine(reg2.Match("dogcat"));      //输出 cat            Console.ReadKey();        }
复制代码

二、字符组

  匹配若干字符之一

[]    //字符串用中括号括起来,表示匹配其中的任一字符,相当于或的意思

  例如:

gr[ea]y    //匹配grey或gray

  其中连字符 - 表示一个范围,例如<h[1-6]> 与 <h[123456]>的作用一致。其他类似的还有[a-z],[A-Z]。

  这里必须要注意的是只有在字符组内部连字符 - 才是元字符,否则它就只匹配普通的连字符-

复制代码
        static void Main(string[] args)        {            Regex reg = new Regex("<h[1-6]>");            string str = "<div><h1>你在他乡还好吗?</h1></div>";            Console.WriteLine(reg.Match(str));      //输出 <h1>            Console.ReadKey();        }
复制代码

三、排除型字符组

  用[^...]取代[...]这个字符组就会匹配任何未列出的字符。

[^...]    //[^...]表示匹配所有方括号里未列出的字符

  例如:

r[^abc]r  //匹配出rar,rbr,rcr之外的任意r*r文本

  下面的例子要注意下,例如正则表达式  q[^u] 不会匹配 Qantas 和 Iraq 这又是为什么呢?

  因为正则表达式是区分大小写的。其次q[^u]要求q后面跟一个非u的字符,即必须包含一个字符。

复制代码
        static void Main(string[] args)        {            Regex reg = new Regex("a[^123456]");            Console.WriteLine(reg.Match("a1a2a3a4a5a6a7")); //输出 a7            Console.ReadKey();        }
复制代码

  在特别强调,排除型字符组表示“匹配一个未列出的字符”而不是“不要匹配列出的字符”。区别在于前者必须要匹配一个。

   另外还要强调一点,在[]里面是没有元字符的,都代表本身的含义,例如[.]就表示匹配一个点.的意思。

四、点号.匹配任意字符  

  元字符.是用来匹配任意字符的字符组的渐变写法。

  .    //匹配任意字符的字符组简便写法

  例如:

  .a    //匹配 Aa 1a ga 等等

   例子:

复制代码
        static void Main(string[] args)        {            Regex reg = new Regex(".c");            Console.WriteLine(reg.Match("abcdefg")); //输出 bc            Console.ReadKey();        }
复制代码

五、多选结构

   | 是一个非常简捷的元字符,它的意思是。依靠它,我们能够把不同的子表达式组合成一个总的表达式,而这个总表达式又能够匹配任意的子表达式。

|    //或 多选分支    选择两者中的一个    注意|将左右两边分为两部分,而不管左右两边有多长多乱

   例如:

gray|grey    //既可匹配gray又可匹配grey    相当于gr[ae]y

  如果将|写在中括号[]里面,那么 | 就不是元字符,它和a e一样,只代表本身字符。

  对于表达式gr(a|e)来说,括号是必须的,如果没有括号,那么gra|ey的意思就成了 gra | ea 即匹配gry或匹配ey。

  再比如 Frist|1st  与  (Fri|1)st  表示的是同一个意思

   C#DEMO:

复制代码
        static void Main(string[] args)        {            Regex reg = new Regex("abc|def");            Console.WriteLine(reg.Match("bcdefg"));     //输出 def            Console.ReadKey();        }
复制代码

  另外要特别注意下,下面的这个例子

  ^from|subject|date:  与  ^(from|subject|date):  之间的区别

  对于前者:只能匹配 ^from 或 subject 或 date:

  对于后者: 能够匹配 ^from: 或 ^subject: 或 ^date:

六、忽略大小写

   当然忽略大小写你可以用 [Aa]bc  取代  abc  ,但是这样不方便。正则表达式提供一个  -i  。用于忽略大小写匹配。

  之前写的是 -i 后来发现是错的,应该是?i  (?i)放在前面就可以了

  (?i)    //用于忽略大小写匹配

  我测试过(?i)写在前面,但是无法匹配,要忽略大小写貌似要通过构造函数的属性设定:

复制代码
        static void Main(string[] args)        {            Regex reg = new Regex("Abc",RegexOptions.IgnoreCase);            Console.WriteLine(reg.Match("abcdefg"));     //输出 abc            Console.ReadKey();        }
复制代码

七、单词分界符

  \b  表示单词分界符

\b  //匹配单词的开始或结束

  代码示例:

复制代码
        static void Main(string[] args)        {            Regex reg = new Regex(@"\bLove\b");            Console.WriteLine(reg.Match("I Love You!"));     //输出 Love            Console.ReadKey();        }
复制代码

八、可选项元素

  ?  代表可选项,把他加在一个字符的后面,就表示此处容许出现这个字符,不过它的出现并非匹配成功的必要条件。

?    //跟在一个字符后面,容许此字符出现0次或1次

  例如:

colou?r    //可以匹配colour或color

  C#Demo:

复制代码
        static void Main(string[] args)        {            Regex reg = new Regex(@"colou?r");            Console.WriteLine(reg.Match("what is color?"));     //输出 color            Console.WriteLine(reg.Match("what is colour?"));     //输出 colour            Console.ReadKey();        }
复制代码

  然后来说一下结合其他元字符使用的情况:

  例如:

  July|Jul  可缩短为  July?

  4th|4    可缩短为  4(th)?

九、重复出现

  加号+和星号*的作用与问号类似,的作用都是限定字符出现的次数。因此问号?加号+星号*这3个元字符统称量词。

?     //可以出现0次或1次    +    //至少要出现1次,可以出现无数次    *    //可以出现0次或出现无数次

  Demo:

复制代码
        static void Main(string[] args)        {            Regex reg = new Regex(@"colo*r");            Console.WriteLine(reg.Match("colooor"));    //输出 colooor            Regex reg2 = new Regex(@"colo*r");            Console.WriteLine(reg2.Match("colr"));    //输出 colr            Regex reg3 = new Regex(@"colo+r");            Console.WriteLine(reg3.Match("colr"));    //输出 空白(啥都不输出,这就是+和*的区别了)            Console.ReadKey();        }
复制代码

十、规定重现次数的范围:区间

  {min,max}  大括号内的数字用于表示某字符允许出现的次数区间。

{min,max}  //大括号内的数字用于表示某字符允许出现的次数区间。

  C# Demo:

复制代码
        static void Main(string[] args)        {            Regex reg = new Regex(@"colo{3,5}r");            Console.WriteLine(reg.Match("colooor"));    //输出 colooor            Regex reg2 = new Regex(@"colo{3,5}r");            Console.WriteLine(reg2.Match("coloor"));    //输出 空白(啥都不输出)  至少3个,但是字符串里只有两个,因此不符合            Console.ReadKey();        }
复制代码

  这里要记住,{}里面的参数不一定要写全两个,也可以仅仅写一个,这样代表仅仅匹配指定的字符数,例如\b{6}\b匹配刚刚6个字母的单词。

  {n,}  匹配n次或更多次,  {5,}  匹配5次以上

十一、括号以及反向引用

  前面已经说过括号的两个作用:限制多选项的范围,将若干字符组合为一个单元,受问号或星号之类的量词作用。现在在来说一种括号的用法,分组,此东西具有记忆的功能,即在正则表达式内部仍然能够回忆上次匹配到的是什么。这个东西用语言说不明白,书本上又是画图又是线的,这里仅仅用一个例子:

复制代码
        static void Main(string[] args)        {            Regex reg = new Regex(@"(\b[A-Za-z]+ +)\1\b");            Console.WriteLine(reg.Match("red color color red"));    //输出 color color            Console.ReadKey();        }
复制代码

  例子解析:首先说明一下括号里面代表什么意思,

  (\b[A-Za-z]+ +)  匹配单词的开始,然后是大小写字母至少1次,然后空格至少1次。说白了就是 空格然后是匹配不区分大小写的一寸字母然后是任意个空格    OK,再来说下\1\b  \b当然就是单词的结尾了,那么\1呢?这个就是分组的作用了,\1代表的就是前面括号里面的东西,也就是一个单词。  因此,整个正则表达式的意思是,匹配间隔了N个空格的重复的单词。不懂也没办法了。

十二、神奇的转义

   \ 转义符它的作用是使元字符失去它的意义,仅仅代表其日常输入中字符的意义。

   C#例子:

复制代码
        static void Main(string[] args)        {            Regex reg = new Regex(@".c");            Console.WriteLine(reg.Match("(acdefg"));    //输出 ac            Regex reg2 = new Regex(@"\.c");            Console.WriteLine(reg2.Match("(acdefg"));    //输出 空白(啥都不输出,说明.已失去了它元字符,代表任意字符的意义)            Regex reg3 = new Regex(@"\.c");            Console.WriteLine(reg3.Match("(.cdefg"));    //输出 .c    它字表它自己,就匹配一个点.了            Console.ReadKey();        }
复制代码

   例如,我要匹配字符 . 字符*  就需要在前面加反斜杠,\.  \*去除它元字符的含义。

   一些需要转义的字符列表    \ * + ? | { [ ( ) ^ $ . # 和 空白

十三、一些其他的元字符

  \w  匹配字母,汉字,数字,下划线

  \W  匹配非字母,非汉字,非数字,非下划线

  \s   匹配空白符

  \S  匹配非空白符

  \d  匹配数字

  \D  匹配非数字

复制代码
static void Main(string[] args)        {            Regex reg = new Regex(@"\w?");            MatchCollection mcoll = reg.Matches("@你s_5");            foreach (Match mat in mcoll)            {                Console.WriteLine(mat.Value);   //输出 空白 你 s _ 5     果然是匹配汉字、字母、下划线、数字            }            Regex reg2 = new Regex(@"\s");            MatchCollection mcoll2 = reg2.Matches("abc def");            foreach (Match mat in mcoll2)            {                Console.WriteLine(mat.Index);   //输出 3    这里要注意一个问题了,在用Matches时,当匹配不到时,会返回Empty,因此,可以认为每次都是匹配到的,但是匹配到空            }            Regex reg3 = new Regex(@"\d");      //匹配数字            Match m2 = reg3.Match("abc5def");            Console.WriteLine(m2.Value);    //输出 5            //以下代码为完全复制上面的代码,只是改了命名与正则            Regex reg4 = new Regex(@"\W?");            MatchCollection mcoll3 = reg4.Matches("@你s_5");            foreach (Match mat in mcoll2)            {                Console.WriteLine(mat.Value);   //输出 @            }            Regex reg5 = new Regex(@"\S");      //匹配非空格            MatchCollection mcoll4 = reg5.Matches("abc def");            foreach (Match mat in mcoll4)            {                Console.WriteLine(mat.Value);   //输出 abcdef    这里要注意一个问题了,在用Matches时,当匹配不到时,会返回Empty,因此,可以认为每次都是匹配到的,但是匹配到空            }            Regex reg6 = new Regex(@"\D");      //匹配非数字            Match m3 = reg6.Match("abc5def");            Console.WriteLine(m3.Value);    //输出 a  Match就是只匹配第一个            Console.ReadKey();        }  
复制代码

  还有,既然学习了正则表达式,就千万不要忘记这一个用法:

  

正则表达式(3) -运算符优先级

正则表达式从左到右进行计算,并遵循优先级顺序,这与算术表达式非常类似。

相同优先级的从左到右进行运算,不同优先级的运算先高后低。下表从最高到最低说明了各种正则表达式运算符的优先级顺序:

运算符描述\转义符(), (?:), (?=), []圆括号和方括号*, +, ?, {n}, {n,}, {n,m}限定符^, $, \任何元字符、任何字符定位点和序列(即:位置和顺序)|替换,"或"操作
字符具有高于替换运算符的优先级,使得"m|food"匹配"m"或"food"。若要匹配"mood"或"food",请使用括号创建子表达式,从而产生"(m|f)ood"。

正则表达式(4) -匹配规则

基本模式匹配

一切从最基本的开始。模式,是正规表达式最基本的元素,它们是一组描述字符串特征的字符。模式可以很简单,由普通的字符串组成,也可以非常复杂,往往用特殊的字符表示一个范围内的字符、重复出现,或表示上下文。例如:

^once

这个模式包含一个特殊的字符^,表示该模式只匹配那些以once开头的字符串。例如该模式与字符串"once upon a time"匹配,与"There once was a man from NewYork"不匹配。正如如^符号表示开头一样,$符号用来匹配那些以给定模式结尾的字符串。

bucket$

这个模式与"Who kept all of this cash in a bucket"匹配,与"buckets"不匹配。字符^和$同时使用时,表示精确匹配(字符串与模式一样)。例如:

^bucket$

只匹配字符串"bucket"。如果一个模式不包括^和$,那么它与任何包含该模式的字符串匹配。例如:模式

once

与字符串

There once was a man from NewYorkWho kept all of his cash in a bucket.

是匹配的。

在该模式中的字母(o-n-c-e)是字面的字符,也就是说,他们表示该字母本身,数字也是一样的。其他一些稍微复杂的字符,如标点符号和白字符(空格、制表符等),要用到转义序列。所有的转义序列都用反斜杠(\)打头。制表符的转义序列是:\t。所以如果我们要检测一个字符串是否以制表符开头,可以用这个模式:

^\t 

类似的,用\n表示"新行",\r表示回车。其他的特殊符号,可以用在前面加上反斜杠,如反斜杠本身用\\表示,句号.用\.表示,以此类推。

字符簇

在INTERNET的程序中,正规表达式通常用来验证用户的输入。当用户提交一个FORM以后,要判断输入的电话号码、地址、EMAIL地址、信用卡号码等是否有效,用普通的基于字面的字符是不够的。

所以要用一种更自由的描述我们要的模式的办法,它就是字符簇。要建立一个表示所有元音字符的字符簇,就把所有的元音字符放在一个方括号里:

[AaEeIiOoUu]

这个模式与任何元音字符匹配,但只能表示一个字符。用连字号可以表示一个字符的范围,如:

[a-z] //匹配所有的小写字母 [A-Z] //匹配所有的大写字母 [a-zA-Z] //匹配所有的字母 [0-9] //匹配所有的数字 [0-9\.\-] //匹配所有的数字,句号和减号 [ \f\r\t\n] //匹配所有的白字符

同样的,这些也只表示一个字符,这是一个非常重要的。如果要匹配一个由一个小写字母和一位数字组成的字符串,比如"z2"、"t6"或"g7",但不是"ab2"、"r2d3" 或"b52"的话,用这个模式:

^[a-z][0-9]$

尽管[a-z]代表26个字母的范围,但在这里它只能与第一个字符是小写字母的字符串匹配。

前面曾经提到^表示字符串的开头,但它还有另外一个含义。当在一组方括号里使用^是,它表示"非"或"排除"的意思,常常用来剔除某个字符。还用前面的例子,我们要求第一个字符不能是数字:

^[^0-9][0-9]$

这个模式与"&5"、"g7"及"-2"是匹配的,但与"12"、"66"是不匹配的。下面是几个排除特定字符的例子:

[^a-z] //除了小写字母以外的所有字符 [^\\\/\^] //除了(\)(/)(^)之外的所有字符 [^\"\'] //除了双引号(")和单引号(')之外的所有字符

特殊字符"." (点,句号)在正规表达式中用来表示除了"新行"之外的所有字符。所以模式"^.5$"与任何两个字符的、以数字5结尾和以其他非"新行"字符开头的字符串匹配。模式"."可以匹配任何字符串,除了空串和只包括一个"新行"的字符串。

PHP的正规表达式有一些内置的通用字符簇,列表如下:

字符簇描述[[:alpha:]]任何字母[[:digit:]]任何数字[[:alnum:]]任何字母和数字[[:space:]]任何空白字符[[:upper:]]任何大写字母[[:lower:]]任何小写字母[[:punct:]]任何标点符号[[:xdigit:]]任何16进制的数字,相当于[0-9a-fA-F]

确定重复出现

到现在为止,你已经知道如何去匹配一个字母或数字,但更多的情况下,可能要匹配一个单词或一组数字。一个单词有若干个字母组成,一组数字有若干个单数组成。跟在字符或字符簇后面的花括号({})用来确定前面的内容的重复出现的次数。

字符簇描述^[a-zA-Z_]$所有的字母和下划线^[[:alpha:]]{3}$所有的3个字母的单词^a$字母a^a{4}$aaaa^a{2,4}$aa,aaa或aaaa^a{1,3}$a,aa或aaa^a{2,}$包含多于两个a的字符串^a{2,}如:aardvark和aaab,但apple不行a{2,}如:baad和aaa,但Nantucket不行\t{2}两个制表符.{2}所有的两个字符

这些例子描述了花括号的三种不同的用法。一个数字,{x}的意思是"前面的字符或字符簇只出现x次";一个数字加逗号,{x,}的意思是"前面的内容出现x或更多的次数";两个用逗号分隔的数字,{x,y}表示"前面的内容至少出现x次,但不超过y次"。我们可以把模式扩展到更多的单词或数字:

^[a-zA-Z0-9_]{1,}$ //所有包含一个以上的字母、数字或下划线的字符串 ^[1-9][0-9]*$ //所有的正数 ^\-{0,1}[0-9]{1,}$ //所有的整数 ^[-]?[0-9]+\.?[0-9]+$ //所有的浮点数

最后一个例子不太好理解,是吗?这么看吧:与所有以一个可选的负号([-]?)开头(^)、跟着1个或更多的数字([0-9]+)、和一个小数点(\.)再跟上1个或多个数字([0-9]+),并且后面没有其他任何东西($)。下面你将知道能够使用的更为简单的方法。

特殊字符"?"与{0,1}是相等的,它们都代表着:"0个或1个前面的内容"或"前面的内容是可选的"。所以刚才的例子可以简化为:

^\-?[0-9]{1,}\.?[0-9]{1,}$

特殊字符"*"与{0,}是相等的,它们都代表着"0个或多个前面的内容"。最后,字符"+"与 {1,}是相等的,表示"1个或多个前面的内容",所以上面的4个例子可以写成:

^[a-zA-Z0-9_]+$ //所有包含一个以上的字母、数字或下划线的字符串 ^[0-9]+$ //所有的正数 ^\-?[0-9]+$ //所有的整数 ^\-?[0-9]*\.?[0-9]*$ //所有的浮点数

当然这并不能从技术上降低正规表达式的复杂性,但可以使它们更容易阅读。

正则表达式(5) -零宽断言与懒惰匹配以及平衡组

小括号的作用

分类     代码/语法     说明

捕获    
      (exp)        匹配exp,并捕获文本到自动命名的组里
      (?<name>exp)   匹配exp,并捕获文本到名称为name的组里,也可以写成(?'name'exp)
      (?:exp)        匹配exp,不捕获匹配的文本,也不给此分组分配组号
零宽断言
      (?=exp)      匹配exp前面的位置
      (?<=exp)      匹配exp后面的位置
      (?!exp)       匹配后面跟的不是exp的位置
      (?<!exp)     匹配前面不是exp的位置
注释
      (?#comment) 这种类型的分组不对正则表达式的处理产生任何影响,用于提供注释让人阅读

要特别注意的是,零宽断言是不占用位置的,也就是说,匹配结果里是不会返回它的。

 (?:exp) 既不捕获匹配的文本,也不给此分组分配组号,这个东西到底有什么用呢?

 (?:exp) 非捕获组,匹配exp的内容,但不捕获到组里

至于作用,一般来说是为了节省资源,提高效率
比如说验证输入是否为整数,可以这样写
^([1-9][0-9]*|0)$
这时候我们需要用到()来限制“|”表示“或”关系的范围,但我们只是要判断规则,没必要把exp匹配的内容保存到组里,这时就可以用非捕获组了
^(?:[1-9][0-9]*|0)$

  有的时候我们不得不用(),而()默认情况下会将其中exp匹配的内容捕获到组里,而有些情况我们只是判断规则,或者后面并不需要对此处()中匹配的内容进行引用时,就没有必要把它捕获到组里了,一方面会造成资源的浪费,另一方面会降低效率,这时候就要用到非捕获组了。

至于这些东西,说是说不明白的,看符号也没用,最好就是上例子。

复制代码
//正则表达式牛逼,名词好牛B,其实好简单        static void Main(string[] args)        {            //(exp) 匹配exp,并捕获文本到自动命名的组里            Regex reg = new Regex(@"A(\w+)A");            Console.WriteLine(reg.Match("dsA123A"));    //输出 A123A            Console.WriteLine(reg.Match("dsA123A").Groups[1]);      //输出123            //(?<name>exp)    匹配exp,并捕获文本到名称为name的组里,也可以写成(?'name'exp)            Regex reg2 = new Regex(@"A(?<num>\w+)A");            Console.WriteLine(reg2.Match("dsA123A").Groups["num"]); //输出123            Regex reg3 = new Regex(@"A(?:\w+A)");            Console.WriteLine(reg3.Match("dsA123A"));            Console.WriteLine("==============================");            //(?=exp)    匹配exp前面的位置  零宽正预测先行断言            Regex reg4 = new Regex(@"sing(?=ing)");     //表达式的意思是,我认为在sing的后面会有ing,如果sing后面紧跟着ing,那么这个sing才匹配成功,注意断言词不会被匹配            Console.WriteLine(reg4.Match("ksingkksingingkkk"));     //输出    sing            Console.WriteLine(reg4.Match("singddddsingingd").Index);   //输出 8   输出8就意味住前面那个sing被没有被匹配            //(?<=exp) 匹配exp后面的位置  零宽度正回顾后发断言            Regex reg5 = new Regex(@"(?<=wo)man");            Console.WriteLine(reg5.Match("Hi man Hi woman"));   //输出 man            Console.WriteLine(reg5.Match("Hi man Hi woman").Index);     //输出 12    掰着手指头算算到底匹配的是哪一个            //(?!exp)    匹配后面跟的不是exp的位置 零宽度负预测先行断言            Regex reg6 = new Regex(@"sing(?!ing)");            Console.WriteLine(reg6.Match("singing-singabc"));   //输出 sing            Console.WriteLine(reg6.Match("singing-singabc").Index); //输出 8  还得掰着手指头算算匹配的是哪一个            //(?<!exp)    匹配前面不是exp的位置 零宽度负回顾后发断言            Regex reg7 = new Regex(@"(?<!wo)man");            Console.WriteLine(reg7.Match("Hi woman Hi man"));   //输出 man            Console.WriteLine(reg7.Match("Hi woman Hi man").Index); //输出 12  算算匹配的是哪一个            //(?#comment)    不对正则表达式的处理产生任何影响,用于提供注释让人阅读            Regex reg8 = new Regex("ABC(?#这只是一段注释而已)DEF");            Console.WriteLine(reg8.Match("ABCDEFG"));   //输出 ABCDEF        }
复制代码

懒惰匹配

代码/语法       说明
*?          重复任意次,但尽可能少重复
+?          重复1次或更多次,但尽可能少重复
??           重复0次或1次,但尽可能少重复
{n,m}?         重复n到m次,但尽可能少重复
{n,}?          重复n次以上,但尽可能少重复

如果你细心的留意到,会发现,其实懒惰匹配符只是在原有限定符后面加了个?以表示尽可能少地匹配的意思。

复制代码
class Program    {        //正则表达式牛逼,名词好牛B,其实好简单        static void Main(string[] args)        {            //懒惰匹配            Regex reg1 = new Regex(@"A(\w)*B");            Console.WriteLine(reg1.Match("A12B34B56B"));    //输出 A12B34B56B //留意到默认是尽可能多地匹配            Regex reg2 = new Regex(@"A(\w)*?B"); //\w重复任意次,但尽可能少                      Console.WriteLine(reg2.Match("A12B34B56B"));   //输出 A12B            Regex reg3 = new Regex(@"A(\w)+?");  //\w重复1次或更多次,但尽可能少            Console.WriteLine(reg3.Match("AB12B34B56B"));        //输出AB 注意此处测试字符串            Regex reg4 = new Regex(@"A(\w)??B");  //\w重复0次或1次,但尽可能少            Console.WriteLine(reg4.Match("A12B34B56B"));    //输出 空白,匹配失败,因为至少也要重复\w两次            Console.WriteLine(reg4.Match("A1B2B34B56B"));   //输出 A1B            Regex reg5 = new Regex(@"A(\w){4,10}?B");       //\w至少重复4次,最多重复10次            Console.WriteLine(reg5.Match("A1B2B3B4B5B"));   //输出 A1B2B3B    到了第4个的时候,恰好第4个字符是3只有匹配3后面的那个B了            Regex reg6 = new Regex(@"A(\w){4,}?");  //\w至少重复4次,最多无上限            Console.WriteLine(reg5.Match("A1B2B3B4B5B"));   //输出 A1B2B3B    到了第4个的时候,恰好第4个字符是3只有匹配3后面的那个B了            Console.ReadKey();        }    }
复制代码

 平衡组

正则表达式平衡组用于匹配左右两边开始,结束符号相等数量的内容
  例如,对于字符串"xx <aa <bbb> <bbb> aa> yy>" 左右两边的< > 是不等的,如果简单的<.+>匹配到的是最外层的开始括号<与结束括号
>之间的内容,但是开始和封闭的括号数量不一致。如果你希望匹配到的是左右括号正常结束的字符串,那么就需要用到平衡组了。

平衡组语法:
  (?'group') 把捕获的内容命名为group,并压入堆栈(Stack)
  (?'-group') 从堆栈上弹出最后压入堆栈的名为group的捕获内容,如果堆栈本来为空,则本分组的匹配失败
  (?(group)yes|no) 如果堆栈上存在以名为group的捕获内容的话,继续匹配yes部分的表达式,否则继续匹配no部分
  (?!) 零宽负向先行断言,由于没有后缀表达式,试图匹配总是失败

复制代码
        static void Main(string[] args)        {            //平衡组 我们现在要匹配最外层的括号的内容            string strTag = "xx <aa <bbb> <bbb> aa> yy>";   //要匹配的目标是 <aa <bbb> <bbb> aa>  ,注意括号数不等            Regex reg = new Regex("<.+>");            Console.WriteLine(reg.Match(strTag));   //输出 <aa <bbb> <bbb> aa> yy>    看到与希望匹配的目标不一致,主要是因为 < 与 > 的数量不相等            Regex reg3 = new Regex("<[^<>]*(((?'Open'<)[^<>]*)+((?'-Open'>)[^<>]+))*(?(Open)(?!))>");            Console.WriteLine(reg3.Match(strTag));  //<aa <bbb> <bbb> aa>   目标正确            //平衡组最常用的例子,匹配HTML,以下是匹配嵌套DIV里面的内容            Regex reg2 = new Regex(@"<div[^>]*>[^<>]*(((?'Open'<div[^>]*>)[^<>]*)+((?'-Open'</div>)[^<>]*)+)*(?(Open)(?!))</div>");            string str = "<a href='http://www.baidu.com'></a><div id='div1'><div id='div2'>你在他乡还好吗?</div></div><p></p>";            Console.WriteLine(reg2.Match(str));  //输出 <div id='div1'><div id='div2'>你在他乡还好吗?</div></div>            Console.ReadKey();        }
复制代码
语法解释:<                         #最外层的左括号    [^<>]*                #最外层的左括号后面的不是括号的内容    (        (            (?'Open'<)    #碰到了左括号,在黑板上写一个"Open"            [^<>]*       #匹配左括号后面的不是括号的内容        )+        (            (?'-Open'>)   #碰到了右括号,擦掉一个"Open"            [^<>]*        #匹配右括号后面不是括号的内容        )+    )*    (?(Open)(?!))         #在遇到最外层的右括号前面,判断黑板上还有没有没擦掉的"Open";如果还有,则匹配失败>                         #最外层的右括号

正则表达式(6) -优化诀窍

1.常识性优化

  1、避免重新编译

  编译和定义正则表达式的次数应尽可能的少。

  2、使用非捕获型括号

  如果不需要引用括号内的文本,请使用非捕获型括号(?:...)。这样不但能节省捕获的时间,而且会减少回溯使用的状态的数量,从两方面提高速度。而且能够进一步的优化,例如消除务必要括号。

  3、不要滥用括号

  在需要的时候使用括号,在其他时候使用括号会阻止某些优化措施。除非你需要知道.*匹配的最后一个字符,否则请不要使用(.*)。

  4、不要滥用字符组

  例如 ^.*[:] 这样会付出处理字符组的代价,而实际上这个式子并需不要用到字符组提供的多字符匹配功能,我认为,当一个字符是元字符时例如 . 或 * 应该使用\.或\*表示,在比如需要 [Ff],应当使用不缺分大小写的匹配,而不是字符组。

  5、使用起始锚点  

  除非是及其罕见的情况,否则以 .* 开头的正则表达式都应该在最前面添加 ^ 或者\A 如果这个正则表达式在某个字符串的开头不能匹配,那么显然在其他位置它也不能匹配。添加锚点无论是手工添加还是通过优化自动添加都能够配合开头字符/字符串/字串识别优化,节省大量不必要的工作。

2.将文本独立出来

   1、从量词中提取必须的元素

  用 xx* 替代 x+ 能够暴露必须匹配的 x 同样,用-----{0,2}代替-{5,7}。

  2、提取多选结构开头的必须元素

  用th(?:is|at)替代(?:this|that),就能暴露出必须的th。如果不同的多选分支的结尾部分相同,我们也可以从右面"提取"。例如(?:optim|standard)ization  。

3.将锚点独立出来

  1、在表达式前面独立出 ^ 和 \G

   ^(?:abc|123)和(^abc|^123)在逻辑上是等价的,但是许多正则引擎指挥对第一个表达式使用开头字符/字符串/字串识别优化。所以第一种办法的效率高得多。

  2、在表达式末尾独立出$

  虽然 abc$|123$ 和 (?:abc|123)$ 在逻辑上是等价的,但优化的表现可能不同。目前只对Perl有效。

正则表达式(7) -简单实例

1.简单表达式

正则表达式的最简单形式是在搜索字符串中匹配其本身的单个普通字符。例如,单字符模式,如 A,不论出现在搜索字符串中的何处,它总是匹配字母 A。下面是一些单字符正则表达式模式的示例:

/a//7//M/

可以将许多单字符组合起来以形成大的表达式。例如,以下正则表达式组合了单字符表达式:a、7 和 M。

/a7M/

请注意,没有串联运算符。只须在一个字符后面键入另一个字符。

2.字符匹配

句点 (.) 匹配字符串中的各种打印或非打印字符,只有一个字符例外。这个例外就是换行符 (\n)。下面的正则表达式匹配 aac、abc、acc、adc 等等,以及 a1c、a2c、a-c 和 a#c:

/a.c/

若要匹配包含文件名的字符串,而句点 (.) 是输入字符串的组成部分,请在正则表达式中的句点前面加反斜扛 (\) 字符。举例来说明,下面的正则表达式匹配 filename.ext:

/filename\.ext/

这些表达式只让您匹配"任何"单个字符。可能需要匹配列表中的特定字符组。例如,可能需要查找用数字表示的章节标题(Chapter 1、Chapter 2 等等)。

3.中括号表达式

若要创建匹配字符组的一个列表,请在方括号([ 和 ])内放置一个或更多单个字符。当字符括在中括号内时,该列表称为"中括号表达式"。与在任何别的位置一样,普通字符在中括号内表示其本身,即,它在输入文本中匹配一次其本身。大多数特殊字符在中括号表达式内出现时失去它们的意义。不过也有一些例外,如:

  • 如果 ] 字符不是第一项,它结束一个列表。若要匹配列表中的 ] 字符,请将它放在第一位,紧跟在开始 [ 后面。
  • \ 字符继续作为转义符。若要匹配 \ 字符,请使用 \\。

括在中括号表达式中的字符只匹配处于正则表达式中该位置的单个字符。以下正则表达式匹配 Chapter 1、Chapter 2、Chapter 3、Chapter 4 和 Chapter 5:

/Chapter [12345]/

请注意,单词 Chapter 和后面的空格的位置相对于中括号内的字符是固定的。中括号表达式指定的只是匹配紧跟在单词 Chapter 和空格后面的单个字符位置的字符集。这是第九个字符位置。

若要使用范围代替字符本身来表示匹配字符组,请使用连字符 (-) 将范围中的开始字符和结束字符分开。单个字符的字符值确定范围内的相对顺序。下面的正则表达式包含范围表达式,该范围表达式等效于上面显示的中括号中的列表。

/Chapter [1-5]/

当以这种方式指定范围时,开始值和结束值两者都包括在范围内。注意,还有一点很重要,按 Unicode 排序顺序,开始值必须在结束值的前面。

若要在中括号表达式中包括连字符,请采用下列方法之一:

  • 用反斜扛将它转义:
    [\-]
  • 将连字符放在中括号列表的开始或结尾。下面的表达式匹配所有小写字母和连字符:
    [-a-z][a-z-]
  • 创建一个范围,在该范围中,开始字符值小于连字符,而结束字符值等于或大于连字符。下面的两个正则表达式都满足这一要求:
    [!--][!-~]

若要查找不在列表或范围内的所有字符,请将插入符号 (^) 放在列表的开头。如果插入字符出现在列表中的其他任何位置,则它匹配其本身。下面的正则表达式匹配1、2、3、4 或 5 之外的任何数字和字符:

/Chapter [^12345]/

在上面的示例中,表达式在第九个位置匹配 1、2、3、4 或 5 之外的任何数字和字符。这样,例如,Chapter 7 就是一个匹配项,Chapter 9 也是一个匹配项。

上面的表达式可以使用连字符 (-) 来表示:

/Chapter [^1-5]/

中括号表达式的典型用途是指定任何大写或小写字母或任何数字的匹配。下面的表达式指定这样的匹配:

/[A-Za-z0-9]/

4.替换和分组

替换使用 | 字符来允许在两个或多个替换选项之间进行选择。例如,可以扩展章节标题正则表达式,以返回比章标题范围更广的匹配项。但是,这并不象您可能认为的那样简单。替换匹配 | 字符任一侧最大的表达式。

您可能认为,下面的表达式匹配出现在行首和行尾、后面跟一个或两个数字的 Chapter 或 Section:

/^Chapter|Section [1-9][0-9]{0,1}$/

很遗憾,上面的正则表达式要么匹配行首的单词 Chapter,要么匹配行尾的单词 Section 及跟在其后的任何数字。如果输入字符串是 Chapter 22,那么上面的表达式只匹配单词 Chapter。如果输入字符串是 Section 22,那么该表达式匹配 Section 22。

若要使正则表达式更易于控制,可以使用括号来限制替换的范围,即,确保它只应用于两个单词 Chapter 和 Section。但是,括号也用于创建子表达式,并可能捕获它们以供以后使用,这一点在有关反向引用的那一节讲述。通过在上面的正则表达式的适当位置添加括号,就可以使该正则表达式匹配 Chapter 1 或 Section 3。

下面的正则表达式使用括号来组合 Chapter 和 Section,以便表达式正确地起作用:

/^(Chapter|Section) [1-9][0-9]{0,1}$/

尽管这些表达式正常工作,但 Chapter|Section 周围的括号还将捕获两个匹配字中的任一个供以后使用。由于在上面的表达式中只有一组括号,因此,只有一个被捕获的"子匹配项"。

在上面的示例中,您只需要使用括号来组合单词 Chapter 和 Section 之间的选择。若要防止匹配被保存以备将来使用,请在括号内正则表达式模式之前放置 ?:。下面的修改提供相同的能力而不保存子匹配项:

/^(?:Chapter|Section) [1-9][0-9]{0,1}$/

除 ?: 元字符外,两个其他非捕获元字符创建被称为"预测先行"匹配的某些内容。正向预测先行使用 ?= 指定,它匹配处于括号中匹配正则表达式模式的起始点的搜索字符串。反向预测先行使用 ?! 指定,它匹配处于与正则表达式模式不匹配的字符串的起始点的搜索字符串。

例如,假设您有一个文档,该文档包含指向 Windows 3.1、Windows 95、Windows 98 和 Windows NT 的引用。再进一步假设,您需要更新该文档,将指向 Windows 95、Windows 98 和 Windows NT 的所有引用更改为 Windows 2000。下面的正则表达式(这是一个正向预测先行的示例)匹配 Windows 95、Windows 98 和 Windows NT:

/Windows(?=95 |98 |NT )/

找到一处匹配后,紧接着就在匹配的文本(不包括预测先行中的字符)之后搜索下一处匹配。例如,如果上面的表达式匹配 Windows 98,将在 Windows 之后而不是在 98 之后继续搜索。

其他示例

下面列出一些正则表达式示例:

正则表达式描述/\b([a-z]+) \1\b/gi一个单词连续出现的位置。/(\w+):\/\/([^/:]+)(:\d*)?([^# ]*)/将一个URL解析为协议、域、端口及相对路径。/^(?:Chapter|Section) [1-9][0-9]{0,1}$/定位章节的位置。/[-a-z]/a至z共26个字母再加一个-号。/ter\b/可匹配chapter,而不能匹配terminal。/\Bapt/可匹配chapter,而不能匹配aptitude。/Windows(?=95 |98 |NT )/可匹配Windows95或Windows98或WindowsNT,当找到一个匹配后,从Windows后面开始进行下一次的检索匹配。/^\s*$/匹配空行。/\d{2}-\d{5}/验证由两位数字、一个连字符再加 5 位数字组成的 ID 号。/<\s*(\S+)(\s[^>]*)?>[\s\S]*<\s*\/\1\s*>/匹配 HTML 标记。

正则表达式(8) -常用实例

1、校验数字的表达式

数字:^[0-9]*$
n位的数字:^\d{n}$
至少n位的数字:^\d{n,}$
m-n位的数字:^\d{m,n}$
零和非零开头的数字:^(0|[1-9][0-9]*)$
非零开头的最多带两位小数的数字:^([1-9][0-9]*)+(.[0-9]{1,2})?$
带1-2位小数的正数或负数:^(\-)?\d+(\.\d{1,2})?$
正数、负数、和小数:^(\-|\+)?\d+(\.\d+)?$
有两位小数的正实数:^[0-9]+(.[0-9]{2})?$
有1~3位小数的正实数:^[0-9]+(.[0-9]{1,3})?$
非零的正整数:^[1-9]\d*$ 或 ^([1-9][0-9]*){1,3}$ 或 ^\+?[1-9][0-9]*$
非零的负整数:^\-[1-9][]0-9″*$ 或 ^-[1-9]\d*$
非负整数:^\d+$ 或 ^[1-9]\d*|0$
非正整数:^-[1-9]\d*|0$ 或 ^((-\d+)|(0+))$
非负浮点数:^\d+(\.\d+)?$ 或 ^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$
非正浮点数:^((-\d+(\.\d+)?)|(0+(\.0+)?))$ 或 ^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$
正浮点数:^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$ 或 ^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$
负浮点数:^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$ 或 ^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$
浮点数:^(-?\d+)(\.\d+)?$ 或 ^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$

2、校验字符的表达式

汉字:^[\u4e00-\u9fa5]{0,}$
英文和数字:^[A-Za-z0-9]+$ 或 ^[A-Za-z0-9]{4,40}$
长度为3-20的所有字符:^.{3,20}$
由26个英文字母组成的字符串:^[A-Za-z]+$
由26个大写英文字母组成的字符串:^[A-Z]+$
由26个小写英文字母组成的字符串:^[a-z]+$
由数字和26个英文字母组成的字符串:^[A-Za-z0-9]+$
由数字、26个英文字母或者下划线组成的字符串:^\w+$ 或 ^\w{3,20}$
中文、英文、数字包括下划线:^[\u4E00-\u9FA5A-Za-z0-9_]+$
中文、英文、数字但不包括下划线等符号:^[\u4E00-\u9FA5A-Za-z0-9]+$ 或 ^[\u4E00-\u9FA5A-Za-z0-9]{2,20}$
可以输入含有^%&',;=?$\”等字符:[^%&',;=?$\x22]+
禁止输入含有~的字符:[^~\x22]+

3、特殊需求表达式

Email地址:^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$
域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?
InternetURL:[a-zA-z]+://[^\s]* 或 ^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$
手机号码:^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$
电话号码(“XXX-XXXXXXX”、”XXXX-XXXXXXXX”、”XXX-XXXXXXX”、”XXX-XXXXXXXX”、”XXXXXXX”和”XXXXXXXX):^($$\d{3,4}-)|\d{3.4}-)?\d{7,8}$
国内电话号码(0511-4405222、021-87888822):\d{3}-\d{8}|\d{4}-\d{7}
身份证号(15位、18位数字):^\d{15}|\d{18}$
短身份证号码(数字、字母x结尾):^([0-9]){7,18}(x|X)?$ 或 ^\d{8,18}|[0-9x]{8,18}|[0-9X]{8,18}?$
帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线):^[a-zA-Z]\w{5,17}$
强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间):^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$
日期格式:^\d{4}-\d{1,2}-\d{1,2}
一年的12个月(01~09和1~12):^(0?[1-9]|1[0-2])$
一个月的31天(01~09和1~31):^((0?[1-9])|((1|2)[0-9])|30|31)$

车牌校验:^[京,津,渝,沪,冀,晋,辽,吉,黑,苏,浙,皖,闽,赣,鲁,豫,鄂,湘,粤,琼,川,贵,云,陕,秦,甘,陇,青,台,内蒙古,桂,宁,新,藏,澳,军,海,航,警][A-Z][0-9,A-Z]{5}$

xml文件:^([a-zA-Z]+-?)+[a-zA-Z0-9]+\\.[x|X][m|M][l|L]$
中文字符的正则表达式:[\u4e00-\u9fa5]
双字节字符:[^\x00-\xff] (包括汉字在内,可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1))
空白行的正则表达式:\n\s*\r (可以用来删除空白行)
HTML标记的正则表达式:<(\S*?)[^>]*>.*?</\1>|<.*? /> (网上流传的版本太糟糕,上面这个也仅仅能部分,对于复杂的嵌套标记依旧无能为力)
首尾空白字符的正则表达式:^\s*|\s*$或(^\s*)|(\s*$) (可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式)
腾讯QQ号:[1-9][0-9]{4,} (腾讯QQ号从10000开始)
中国邮政编码:[1-9]\d{5}(?!\d) (中国邮政编码为6位数字)
IP地址:\d+\.\d+\.\d+\.\d+ (提取IP地址时有用)IP地址:((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))

4、钱的输入格式:

  • 有四种钱的表示形式我们可以接受:”10000.00″ 和 “10,000.00″, 和没有 “分” 的 “10000″ 和 “10,000″:^[1-9][0-9]*$
  • 这表示任意一个不以0开头的数字,但是,这也意味着一个字符”0″不通过,所以我们采用下面的形式:^(0|[1-9][0-9]*)$
  • 一个0或者一个不以0开头的数字.我们还可以允许开头有一个负号:^(0|-?[1-9][0-9]*)$
  • 这表示一个0或者一个可能为负的开头不为0的数字.让用户以0开头好了.把负号的也去掉,因为钱总不能是负的吧.下面我们要加的是说明可能的小数部分:^[0-9]+(.[0-9]+)?$
  • 必须说明的是,小数点后面至少应该有1位数,所以”10.”是不通过的,但是 “10″ 和 “10.2″ 是通过的:^[0-9]+(.[0-9]{2})?$
  • 这样我们规定小数点后面必须有两位,如果你认为太苛刻了,可以这样:^[0-9]+(.[0-9]{1,2})?$
  • 这样就允许用户只写一位小数。下面我们该考虑数字中的逗号了,我们可以这样:^[0-9]{1,3}(,[0-9]{3})*(.[0-9]{1,2})?$
  • 1到3个数字,后面跟着任意个 逗号+3个数字,逗号成为可选,而不是必须:^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$
  • 备注:这就是最终结果了,别忘了”+”可以用”*”替代。如果你觉得空字符串也可以接受的话(奇怪,为什么?)最后,别忘了在用函数时去掉去掉那个反斜杠,一般的错误都在这里

正则表达式(9) -Regex类

一、属性

CacheSize   获取或设置已编译的正则表达式的当前静态缓存中的最大项数。 默认是15个,最近使用的15个会存在缓存中,避免重新创建。当有第16个进来会替换掉第         1个。保持15个。
Options    返回传入 Regex 构造函数的选项。
RightToLeft  获取一个值,该值指示正则表达式是否从右向左进行搜索。

二、方法

CompileToAssembly   已重载。 编译正则表达式,并将其保存到单个程序集的磁盘中。
Escape          通过替换为转义码来转义最小的元字符集(\、*、+、?、|、{、[、(、)、^、$、.、# 和空白)。
GetGroupNames     返回正则表达式的捕获组名数组。
GetGroupNumbers    返回与数组中的组名相对应的捕获组号的数组。
GroupNameFromNumber   获取与指定组号相对应的组名。
GroupNumberFromName   返回与指定组名相对应的组号。
InitializeReferences    基础结构。 由 CompileToAssembly 方法生成的 Regex 对象使用。
IsMatch         已重载。 指示正则表达式在输入字符串中是否找到匹配项。
Match          已重载。 在输入字符串中搜索正则表达式的匹配项,并将精确结果作为单个 Match 对象返回。
Matches         已重载。 在输入字符串中搜索正则表达式的所有匹配项并返回所有成功的匹配,就像多次调用 Match 一样。
Replace         已重载。 在指定的输入字符串内,使用指定的替换字符串替换与某个正则表达式模式匹配的字符串。
Split            已重载。 在由正则表达式匹配项定义的位置将输入字符串拆分为一个子字符串数组。
Unescape          取消转义输入字符串中的任何转义字符。
UseOptionC       基础结构。 由 CompileToAssembly 方法生成的 Regex 对象使用。
UseOptionR       基础结构。 由 CompileToAssembly 方法生成的 Regex 对象使用。

   代码示例:

复制代码
static void Main(string[] args)        {            Regex reg = new Regex(@"\d+");            Regex.CacheSize = 1000;             //最大静态缓存项数,不知道用来干嘛的            Console.WriteLine(reg.Options);     //输出 Singleline 构造函数中的选项            Console.WriteLine(reg.RightToLeft); //输出 False  是否从右向左搜索            Console.WriteLine(Regex.Escape(@"\d+"));    //输出 \\d\+  这个Escape    方法用于动态获取的变量生成的正则表达式,这时如果变量中含有正则中的元字符,会被解析成元字符,就可能会导致正则编译不通过,从而导致程序异常,需要对变量进行转义处理。比如根据用户输入的id获取Html控件,如果这个用户输入的控件id含有元字符,那么就会抛异常,这个时候就可以用Escape转码一下            Console.WriteLine(Regex.Unescape(@"\\d\+"));    //输出    \d+     反转码,获取转码之前的字符串            Console.WriteLine(reg.IsMatch("123"));      //输出 True            Console.WriteLine(reg.IsMatch("abc"));      //输出 False            Console.WriteLine(reg.Match("1a"));         //输出 1  返回精确的匹配到的结果            MatchCollection col = reg.Matches("12a34b45d");  //match与matches的区别在于match返回第一个匹配,而matches返回全部的匹配            foreach (var c in col)            {                Console.WriteLine(c.ToString());        //输出 12 34 45            }            Console.WriteLine(reg.Replace("ab5cd","k"));    //输出abkcd 替换正则表达式匹配到的字符,第二个参数是用于替换的字符            Console.WriteLine(reg.Replace("a1b2c3d", "k"));    //输出akbkckdk            string[] strArr = reg.Split("ab2cd");   //用匹配到的字符将字符串分割成两个字符串数组            foreach (string str in strArr)            {                Console.WriteLine(str);     //输出 ab cd            }            Regex reg2 = new Regex(@"(?<数字分组>\d+)abc");            int[] intArr = reg2.GetGroupNumbers();            foreach (int i in intArr)            {                Console.WriteLine(i);   //输出0 1     0始终代表整个表达式,1就是你自己括起来的我那组            }            string[] strGroup = reg2.GetGroupNames();            foreach (string str in strGroup)            {                Console.WriteLine(str);     //输出0   数字分组    至于整个表达式指定不指定意义都不大,反正你肯定知道0是整个组            }            Console.WriteLine(reg2.GroupNameFromNumber(1)); //输出 数字分组,根据组号,获取组名            Console.WriteLine(reg2.GroupNumberFromName("数字分组"));    //输出 1  根据组名获取组号            Console.ReadKey();        }
复制代码

正则表达式(10) -Match类

Regex在匹配的时候,常常会返回一个Match类的对象,今天就来看看怎么玩这个对象。

一、属性

Captures   按从里到外、从左到右的顺序获取由捕获组匹配的所有捕获的集合(如果正则表达式用 RegexOptions..::.RightToLeft 选项修改了,则顺序为按从里到外、       从右到左)。该集合可以有零个或更多的项。
Empty     获取空组。所有失败的匹配都返回此空匹配。
Groups      获取由正则表达式匹配的组的集合。
Index      原始字符串中发现捕获的子字符串的第一个字符的位置。
Length      捕获的子字符串的长度。
Success     获取一个值,该值指示匹配是否成功。
Value     从输入字符串中获取捕获的子字符串。

二、方法

NextMatch     从上一个匹配结束的位置(即在上一个匹配字符之后的字符)开始返回一个包含下一个匹配结果的新 Match。
Result       返回对指定替换模式的扩展。
Synchronized    返回一个与提供的实例等效的 Match 实例,该实例适合在多个线程间共享。
ToString       从输入字符串中获取捕获的子字符串。 (继承自 Capture。)

复制代码
static void Main(string[] args)        {            Regex reg = new Regex(@"(?<数字分组>\d+)abc");            Match m = reg.Match("s123abcdefg");            Console.WriteLine(m.Success);   //输出 True   指示匹配是否成功            Console.WriteLine(m.Value);     //输出 123abc 获取匹配到的子字符串            Console.WriteLine(m.Length);    //输出 6  匹配的子字符串的长度,其实m.value.Length不就行了吗            Console.WriteLine(m.Index);     //输出 1  获取匹配到的子字符串的第一个字符在整个输入字符串的位置            GroupCollection GColl = m.Groups;            foreach (Group g in GColl)            {                                   //        整个组  自定义组                Console.WriteLine(g.Success);   //输出    True    True                Console.WriteLine(g.Index);     //输出    1       1                Console.WriteLine(g.Length);    //输出    6       3                Console.WriteLine(g.Value);     //输出    123abc  123            }            Console.WriteLine(Match.Empty);     //输出 空白(啥都不输出,空匹配,所有失败的匹配都返回此空匹配)            CaptureCollection CColl = m.Captures;            foreach (Capture c in CColl)            {                Console.WriteLine(c.Index);     //输出 1                Console.WriteLine(c.Length);    //输出 6                Console.WriteLine(c.Value);     //输出 123abc            }            Regex reg2 = new Regex(@"\d+");            Match m2 = reg2.Match("123abc456");            Console.WriteLine(m2.Value);    //输出 123            Match m3 = m2.NextMatch();            Console.WriteLine(m3.Value);    //输出 456            Match m4 = Match.Synchronized(m3);  //获取一个与实例等效的Match实例用于多线程共享            Console.WriteLine(m4.Value);    //输出 456            Console.WriteLine(m3.ToString());   //输出 456            Regex reg3 = new Regex(@"\d+");            Match m5 = reg3.Match("123ABC");            Console.WriteLine(m5.Result("$'")); //输出 ABC  不要迷惑 这个需要了解下replacement  http://www.cnblogs.com/kissdodog/archive/2013/04/25/3043173.html            Console.ReadKey();        }
复制代码

  另外再附上两个,输入字符串中匹配所有符合条件的例子:

复制代码
static void Main(string[] args)        {            Regex reg = new Regex(@"\d+");             //第一种方法是利用Matches方法,返回所有匹配到的字符串的集合            MatchCollection MColl = reg.Matches("123abc456");            foreach (Match m in MColl)            {                Console.WriteLine(m.Value);     //输出 123 456            }            //第二种方法是利用Match类的NextMatch()方法            Match m2 = reg.Match("123abc456");            while (m2.Success)            {                Console.WriteLine(m2.Value);    //同样输出 123 456                m2 = m2.NextMatch();            }            Console.ReadKey();        }
复制代码

 

正则表达式(11) -RegexOptions枚举

在创建Regex类的实例时,构造函数的重载中有一个要求传入RegexOptions的一个枚举值,我相信这个枚举一定非常有用,否则不会要求在构造函数中传入。今天就来看一看这个枚举的作用。

  我们干脆把代码敲出来看一看:

复制代码
    // 摘要:    //     提供用于设置正则表达式选项的枚举值。    [Flags]    public enum RegexOptions    {        // 摘要:        //     指定不设置选项。        None = 0,        //        // 摘要:        //     指定不区分大小写的匹配。        IgnoreCase = 1,        //        // 摘要:        //     多行模式。更改 ^ 和 $ 的含义,使它们分别在任意一行的行首和行尾匹配,而不仅仅在整个字符串的开头和结尾匹配。        Multiline = 2,        //        // 摘要:        //     指定有效的捕获仅为形式为 (?<name>...) 的显式命名或编号的组。这使未命名的圆括号可以充当非捕获组,并且不会使表达式的语法 (?:...)        //     显得笨拙。        ExplicitCapture = 4,        //        // 摘要:        //     指定将正则表达式编译为程序集。这会产生更快的执行速度,但会增加启动时间。在调用 System.Text.RegularExpressions.Regex.CompileToAssembly(System.Text.RegularExpressions.RegexCompilationInfo[],System.Reflection.AssemblyName)        //     方法时,不应将此值分配给 System.Text.RegularExpressions.RegexCompilationInfo.Options        //     属性。        Compiled = 8,        //        // 摘要:        //     指定单行模式。更改点 (.) 的含义,使它与每一个字符匹配(而不是与除 \n 之外的每个字符匹配)。        Singleline = 16,        //        // 摘要:        //     消除模式中的非转义空白并启用由 # 标记的注释。但是,System.Text.RegularExpressions.RegexOptions.IgnorePatternWhitespace        //     值不会影响或消除字符类中的空白。        IgnorePatternWhitespace = 32,        //        // 摘要:        //     指定搜索从右向左而不是从左向右进行。        RightToLeft = 64,        //        // 摘要:        //     为表达式启用符合 ECMAScript 的行为。该值只能与 System.Text.RegularExpressions.RegexOptions.IgnoreCase、System.Text.RegularExpressions.RegexOptions.Multiline        //     和 System.Text.RegularExpressions.RegexOptions.Compiled 值一起使用。该值与其他任何值一起使用均将导致异常。        ECMAScript = 256,        //        // 摘要:        //     指定忽略语言中的区域性差异。有关更多信息,请参见 Performing Culture-Insensitive Operations in the        //     RegularExpressions Namespace。        CultureInvariant = 512,    }
复制代码

  由代码可以看出这是一个标志枚举。

  其实把代码复制出来之后,感觉也不是那么难懂,都是一些基本的指示。

复制代码
None = 0,         //指定不设置选项。IgnoreCase = 1,     //指定不区分大小写的匹配。Multiline = 2,          //多行模式。更改 ^ 和 $ 的含义,使它们分别在任意一行的行首和行尾匹配,而不仅仅在整个字符串的开头和结尾匹配。ExplicitCapture = 4,    //指定有效的捕获仅为形式为 (?<name>...) 的显式命名或编号的组。这使未命名的圆括号可以充当非捕获组,并且不会使表达式的语法 (?:...)显得笨拙。Compiled = 8,       //指定将正则表达式编译为程序集。这会产生更快的执行速度,但会增加启动时间。在调用 System.Text.RegularExpressions.Regex.CompileToAssembly(System.Text.RegularExpressions.RegexCompilationInfo[],System.Reflection.AssemblyName)方法时,不应将此值分配给属性。Singleline = 16,    //指定单行模式。更改点 (.) 的含义,使它与每一个字符匹配(而不是与除 \n 之外的每个字符匹配)。IgnorePatternWhitespace = 32 //消除模式中的非转义空白并启用由 # 标记的注释。但是,System.Text.RegularExpressions.RegexOptions.IgnorePatternWhitespace值不会影            响或消除字符类中的空白。RightToLeft = 64  //指定搜索从右向左而不是从左向右进行。ECMAScript = 256,   //为表达式启用符合 ECMAScript 的行为。该值只能与 System.Text.RegularExpressions.RegexOptions.IgnoreCase、System.Text.RegularExpressions.RegexOptions.Multiline 和 System.Text.RegularExpressions.RegexOptions.Compiled 值一起使用。该值与其他任何值一起使用均将导致异常。CultureInvariant = 512    //指定忽略语言中的区域性差异。
复制代码








0 0
原创粉丝点击