一些简单的正则语法规则

在研究C#爬虫的时候遇到了许许多多的问题,暂时还没啥成果,先记下一些心得,日后好翻看。

正则表达式的基本语法规则:

\b:代表着单词的开头或结尾,也就是单词的分界处。
. :表示匹配除了换行符以外的任意字符
* :表示的是数量,它指定前面的内容可以重复使用任意次,以使整个表达式得到匹配。.*连在一起就表示任意数量的不包含换行的字符。
例子:\bhi\b.*\bLucy\b表示:先是一个单词hi,然后是任意个字符(但是不能换行),最后是lucy这个单词
\d :匹配一位数字
例:0\d{2}-\d{8}。 这里\d后面的{2}({8})的意思是前面\d必须连续重复匹配2次(8次)
\s :匹配任意的空白符,包括空格、制表符(Tab),换行符,中文全角空格等
\w :匹配字母或数字或下划线或汉字等
例子:
    \ba\w*\b 匹配以字母a开头的单词——先是某个单词开始处(\b),然后是字母a,然后是任意数据的字母或数字(\w*),最后是单词的结束处(\b)
    \d+ 匹配一个或更多连续的数字。这里的+是和*类似的元字符,不同的是*匹配重复任意次(可能是0次),而+则匹配重复1次或更多次
    \b\w{6}\b 匹配刚好6位的单词
元字符^和$都匹配一个位置,这和\b有点类似
^匹配你要用来查找的字符串的开头,$匹配结尾,验证QQ或者手机号的时候可以使用。表示的是整个字符串都要匹配这个正则
例:^\d{5,12}$ 表示整个输入字符串必须以数字开头,重复次数不能小于5次,不能多于12次,否则都不匹配。
字符转义:
\ 使用这个字符来取消这些特殊字符的特殊意义。
例:deerchao\.cn 匹配deerchao.cn       c:.\\Windows 匹配 c:\Windows

重复
Windows\d+ 匹配Windows后面跟一个或更多数字
^\w+    匹配以字母或数字或下划线或汉字开头的(除去空格)多个字符。或者说匹配一行的第一个单词(或整个字符串的第一个单词,具体匹配哪个意思得看选项设置)


?  表示前面的匹配字符能出现0次或1次

[]  这个字符里面的任意一个字符    例:[aeiou]匹配任意一个元音节字母  [.?!]匹配标点符号(.或?或!)。
也可以指定字符范围 例:[0-9]代表的含义与\d完全一致。匹配任意数字。[a-z0-9A-Z]与\w完全一致(只考虑英文的话)

例子:\(?0\d{2}[) -]?\d{8}    这个表达式可以匹配几种格式的电话号码,像(010)88886666,或022-22334455等
分析一下:首先是一个转义字符\(,他能出现0次或者1次(?),然后是一个0,后面跟2个数字(\d{2})然后是)或者-或者空格中的
一个,他出现的次数是0或者1(?),最后是8个数字。
分支条件
|     表示有几种规则,如果满足其中任意一种规则就应该当成匹配,具体做法是使用 | 将不同的规则分隔开
例子:
0\d{2}-\d{8}|0\d{3}-\d{7}   这个表达式能匹配两种以连字号分隔的电话号码:一种是三位区号,8位本地号(如010-12345678),一种是4位区号,7位本地号(0376-2233445)。
\d{5}-\d{4}|\d{5}这个表达式用于匹配美国的邮政编码 。分支条件时要注意各个条件的顺序。
\d{5}|\d{5}-\d{4}只会匹配5位的邮编(以及9位邮编的前5位)。原因是匹配分枝条件时,将会从左到右地测试每个条件,如果满足了某个分枝的话,就不会去再管其它的条件了。
反义:
  查找除了数字以外,其他任意字符都行的情况,这时需要用到反义,注意前三个是大写字母,大小写表示的含义正好相反:
\W:匹配任意一个不是字母,数字,下划线,汉字的字符
\S :匹配任意不是空白符的字符
\D :匹配任意非数字的字符
[^x]:匹配除了x以外的任意字符
例子:
\S+ 匹配不包含空白字符的字符串。
<a[^>]+> 匹配用尖括号括起来的以a开头的字符串
a[^\d]+[^>] 匹配a后面跟的不是任意一个或几个数字([^\d]+)再后面不是>([^>])的字符 如<abcdef>匹配出来的结果是abcdef
分组:
重复单个字符直接在字符后面添加限定符就行了,要想重复多个字符可以使用子表达式(),就可以指定这个子表达式的重复次数,也可以做一些其他的操作
例子:
(\d{1,3}\.){3}\d{1,3}是一个简单的IP地址匹配表达式。
解析:\d{1,3}匹配1到3位数字。
         (\d{1,3}\.){3}匹配三位数字加上一个英文句号(这个整体也就是这个分组)重复三次,最后再加上一个一到三位的数字(\d{1,3})。
这个表达式有点错误256.300.888.999这种不可能存在的ip地址也会匹配出来
匹配一个正确的Ip:((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5][01]?\d\d?)。
解析:以2开头后面跟一个0-4之间的数字(2[0-4])后面再跟一个任意数字(\d) 或者(|)  25后面跟一个0-5的数字[0-5] 或者(|)  0或1[0-1]出现0次或1次,后面跟一个数字(\d),后面再跟一个数字出现0或1次(\d?),这个分组重复三次{3}。  ((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}  后面再匹配一个三位数。


后向引用:
使用小括号指定一个子表达式之后,匹配这个子表达式的文本(也就是此分组捕获的内容),可以在表达式或其他程序中作进一步的处理。默认情况下,每个分组会自动拥有一个组号,规则是:从左到右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。分组0代表整个表达式。

后向引用:用于重复搜索前面某个分组匹配的文本。例如:\1表示分组1匹配到的文本
    例子:\b(\w+)\b\s+\1\b 可以用来匹配重复的单词,像go go 这样的可以匹配到 go cat go这样的是匹配不到的
解析:表达式首先是一个单词,也就是单词开头和结尾处之间多于一个字母和数字(\b(\w+)\b),这个单词会被捕获到编号1的分组中。然后是一个或几个空白符(\s+),最后是分组1中捕获的内容(\1),也就是前面匹配到的那个单词

也可以自己指定子表达式的组名。要指定一个子表达式的组名,可以使用这样的语法(?<Word>\w+)或者(?'Word'\w+),这样就把\w+的组名指定为Word了。要反向引用这个分组捕获的内容,可以使用\k<Word>或者\k'Word'。
所以上面的例子可以写成:\b(?'Word'\w+)\b\s+\k'Word'\b

常用分组语法
    (exp)  匹配exp,并捕获文本到自动命名的组里
    (?<name>exp),匹配exp,并捕获文本到名称为name的组里
    (?:exp), 匹配exp,不捕获匹配的文本,也不给此分组分配组号
零宽断言:
像\b,^,$  那样用于指定一个位置,这个位置应该满足一定的条件(即断言),因此他们也被称为零宽断言。

(?=exp) 也叫零宽正预测先行断言,它断言自身出现的位置的后面能匹配表达式exp
例子:\b\w+(?=ing\b),匹配以ing单词结尾的前面部分(除了ing以外的部分),如查找I'm singing while you're dancing.时,它会匹配sing和danc,也就是说能匹配ing结尾的单词ing前面的部分

(?<=exp) 也叫零宽度正预测后发断言,他断言自身出现的位置的前面能匹配表达式exp。
例子:(?<=\bre)\w+\b 会匹配以re开头的单词的后半部分(除了re以外的部分),例如在查找reading a book时,它匹配ading,也就是将re后面的部分截取出来

例子:(?<=\s)\d+(?=\s)  匹配以空白字符间隔的数字

负向零宽断言:
    我们只想确保某个字符没有出现,并不像去匹配它时可以使用负向零度断言
例子:我们想查找这样一个单词,它里面出现了字母q,但是q后面跟的不是字母u,我们可以这样尝试:
不使用负向零宽断言:
    \b\w*q[^u]\w*\b 匹配包含后面不是字母u的字母q的单词,这样的话,像Iraq fighting这样的就全部匹配出来了
使用负向零宽断言:
    \b\w*q(?!u)\w*\b 他只匹配一个位置,并不消费任何字符
零宽度负预测先行断言(?!exp),断言此位置的后面不能匹配表达式exp
    例子:\d{3}(?!\d)匹配三位数字,而且这三位数字的后面不能是数字;\b((?!abc)\w)+\b匹配不包含连续字符串abc的单词
同理,我们可以用(?<!exp),零宽度负回顾后发断言来断言此位置的前面不能匹配表达式exp:(?<![a-z])\d{7}匹配前面不是小写字母的七位数字。

断言使用复杂小例子:
    匹配包含属性的简单HTML标签内的内容。(?<=<(\w+)>).*(?=<\/\1>)
解析:(?<=<(\w+)>)指定了被尖括号括起来的单词(比如可能是一个<b>),然后是.*(任意的字符串),最后是一个后缀(?=<\/\1>),\/是一个转义,\1是引用前面捕获的组,这个匹配的内容有可能是<b></b>之间的内容,不包含<b></b>
贪婪与懒惰:
在使用正则的重复限定符时,正则会匹配尽可能多的字符
例子:a.*b 如果我们搜索aabab的话他会匹配整个字符串aabab,我们叫做贪婪匹配
匹配尽可能少的字符,我们叫做懒惰匹配。贪婪匹配转换成懒惰匹配只需要在后面加一个?
.*?意味着匹配任意数量的重复,但是在能使整个匹配成功的前提下使用最少的重复
a.*?b 匹配最短的,以a开始,以b结束的字符串。如果应用于aabab的话,他会匹配aab和ab
平衡组,递归匹配()

<                   #最外层的左括号
  [^<>]*            #它后面非括号的内容
  (
      (
        (?'Open'<)  #左括号,压入"Open"
        [^<>]*      #左括号后面的内容
      )+
      (
        (?'-Open'>) #右括号,弹出一个"Open"
        [^<>]*      #右括号后面的内容
      )+
  )*
  (?(Open)(?!))     #最外层的右括号前检查
                    #若还有未弹出的"Open"
                    #则匹配失败

>                #最外层的右括号
平衡组的一个最常见的应用就是匹配HTML,下面这个例子可以匹配嵌套的<div>标签:
<div[^>]*>[^<>]*(((?'Open'<div[^>]*>)[^<>]*)+((?'-Open'</div>)[^<>]*)+)*(?(Open)(?!))</div>

博客参考:https://deerchao.cn/tutorials/regex/regex.htm

posted @ 2019-12-17 20:36  码不够的张小墨  阅读(404)  评论(0编辑  收藏  举报