正则表达式与模式匹配以及捕获

时间:2021-06-29 05:31:47

      首次接触正则表达式是在工作中接触到ruby语言脚本开发的时候,鉴于工作中经常需要对reply内容中的相关字段进行提取和比较,正则表达式就成为必须掌握的,但仅仅了解正则表达式的基本规则还不能完成上面说的这个工作,我们还需要了解跟这个密切相关的另外两个概念:就是模式匹配和捕获,因为此为自学摸索,如果表述错误或者失当的地方,请各位大佬指正:

正则表达式是用来匹配字符串的,字符串匹配成功后,我们还可以根据需求取其中的某个或者是某几个子字符串(捕获)进行其他的操作。下面先来介绍一下正则表达式的语法:

字符                       . \  [...]

预定义字符集        \d \D \s \S \w \W

数量词                   * + ? {m} {m,n}

边界匹配             ^ $  \A \Z \b \B

逻辑分组             |    (....)   (?P<name> ...)    \<name>   (?P<name>)

特殊构造             (?:...)   (?iLmsux)  (?#...)  (?=...)   (?!...)   (?<=...)  (?<!...)    (?(id/name)yes_pattern|no_parttern)

语法

说明

表达式实例

匹配字符串

字符

. 匹配除换行"\n"外的任意字符串 abc abc
\ 转义字符,使后一个字符改变原来的意思 a\\c a\c
[...] 字符集,对应的位置可以是字符集中任意字符,字符集中的字符可以逐个列出,也可以给出范围,如[abc]或[a-c]。第一个字符如果是^则表示取反,如[^abc]表示不是abc中的其他字符。所有的特殊的字符在字符集中都失去其原有的特殊含义。在字符集中使用^、]或-,可以使用转义字符匹配它们 a[bcd]e

abe

ace

ade

预定义字符集

\d 数字:[0-9] a\dc a1c
\D 非数字:[^0-9] a\Dc abc
\s 空白字符:[<空格>\t\r\n\f\v] a\sc a c
\S 非空白字符:[^\s] a\Sc abc
\w 单词字符:[a-zA-z0-9_] a\wc abc
\W 非单词字符:[^\w] a\Wc a c

数量词

* 匹配一个字符串0或无限次 abc*

ab

abc

abccc

+ 匹配一个字符串1次或无限次 abc+

abc

abccc

? 匹配一个字符串0次或1次

abc?

ab

abc

{m} 匹配一个字符串m次 abc{2} abcc
{m,n} 匹配一个字符串m到n次 abc{2,3}

abcc

abccc

边界匹配

^ 匹配字符串开头 ^abc abc
$ 匹配字符串末尾 abc$ abc
\A 匹配字符串开始 \Aabc abc
\Z 匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串 abc\Z abc
\b 匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。    
\B 匹配非单词边界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。    

逻辑分组

| 匹配|表达式左右的任意一个 abc|def

abc

def

(...) 作为分组,每遇到一个(,分组编号加1,使用分组的好处是匹配的子串会保存到一个子组,便于以后使用 (abc){2} abcabc
(?P<name>...) 分组除原有编号外,再加一个别名 (?P<id>abc){2} abcabc
\<number> 引用编号为number的分组匹配到的字符串 (\d)ab\1

1ab1

5ab5

(?P=name) 应用别名为name的分组匹配到的字符串 (?P<id>abc)ee(?P=name) abceeabc

特殊构造(不分组)

(?:...) (...)的不分组版本,用于|或后接数量词 (?:abc){2} abcabc
(?iLmsux) iLmsux中的每个字符代表正则表达式的一种匹配模式,只能用在正则表达式开头,可选多个 (?i)abc AbC
(?#...) 将#后面的字符当做注释忽略 abc(?#comment)def abcdef
(?=...) 之后的字符串表达式需要匹配才能成功,不消耗字符串内容 a(?=\d) 后面是数字的a
(?!...) 之后的字符串表达式需要不匹配才能成功,不消耗字符串内容 a(?!\d) 后面不是数字的a
(?<=...) 之前的字符串表达式需要匹配才能成功,不消耗字符串内容 (?<=\d)a

前面是数字的a

(?<!...) 之前的字符串表达式需要不匹配才能成功,不消耗字符串内容 (?<!\d)a 前面不是数字的a

(?(id/name)yes_

pattern|no_parttern)

如果匹配到分组为id或别名name的字符串成功匹配,则需要匹配yes_pattern

不成功,怎需要匹配no_pattern

(\d)abc(?(1)\d|def)

1abc3

abcdef

修饰符中  i  当匹配文本的时候忽略大小写

                o 只执行一次#{}插值,正则表达式在第一次时就进行判断

                x 忽略空格,允许在整个表达式中放入空白符和注释。

                m 匹配多行,把换行字符识别为正常字符。

                u,e,s,n   把正则表达式解释为Unicode(utf-8)、EUC、SJIS或ASCII。如果没有指定修饰符,则认为正则表达式使用的源编码。

 

贪婪模式和非贪婪模式

贪婪模式是尽可能多的匹配字符串,python默认为贪婪模式,非贪婪模式尽可能少的匹配字符串,在正则表达式后面加个?表示非贪婪模式。例如:字符串abcccb,贪婪模式正则表达式为ab.*c,非贪婪模式的正则表达式为ab.*?c,贪婪模式结果为abccc,非贪婪模式结果为abc,再比如字符串abbb,贪婪模式正则表达式为ab?,非贪婪模式正则表达为ab??,贪婪模式结果为ab,非贪婪结果为a。

在ruby中,正则表达式是一种介于斜杠之间或者介于%r后的任意分隔符之间的模式,以下面的邮件头信息为例:

Date: Tue, 30 Jul 2013 16:53:17 +0800
From: =?UTF-8?B?YmFpZHU=?=<passport@baidu.com>
To: =?UTF-8?B?aG9uZ3RlbnpvbmVAZm94bWFpbC5jb20=?=<hongtenzone@foxmail.com>
Subject: =?UTF-8?B?55m+5bqm5LqR6YCB5L2gMTAwR+WtmOWCqOepuumXtOmAmuefpQ==?=
MIME-Version: 1.0
Content-Type: text/html;
    charset="UTF-8"
Content-Transfer-Encoding: base64

首先,将上述信息赋值给变量str,则str =~ /Date:.*/将匹配到Date整行;

也可写成str =~ %r!Date:.*!

上面的表达方式比较粗糙,为了更精细的匹配可以写成下面的格式:

str =~ /Date:\s\w+,\d+\s\w+\s\d+\s\d+:\d+:\d+\s\d++\d+/

Python的正则表达式的模块是‘re’,例如在字符串s中找字符串a,则可以写成

import re
s='asdf125'

re.findall(r'df',s)
Out[5]: ['df']

这里用到函数findall(rule,target[,flag])

同理,re.findall(r!Date:.*!,str)可以匹配到发件时间信息;

           re.findall(r[From:.*],str)可以匹配到发件人信息;

在上面的例子中我们发现python通过findall函数返回的是符合模式的字符串内容,那如果我们想获取符合模式的相关信息的内容,该怎么办呢?那就用到捕获:

str =~ /Date:\s(\w+),(\d+)\s(\w+)\s\d+\s\d+:\d+:\d+\s\d++\d+/

如上,如果我们print $1,$2,$3,则会对应输出 Tue 30 Jul三个信息

python的表达和返回则如下:是一个元素类型为元组的列表。

re.findall(r'Date:\s(.*)(\d+):(\d+):(\d+).*', str)
Out[9]: [('Tue, 30 Jul 2013 1', '6', '53', '17')]

要想取出齐总的元素,可以用:

result = re.findall(r'Date:\s(.*)(\d+):(\d+):(\d+).*', str)

print(result[0][0])\print(result[0][1])...