正则表达式(regular expression)这玩意儿多 nb 就不用说了,python 用 re 模块来支持正则
首先是一些正则表达式的概念
1. 通配符 .
2. 多字符选择 [...]
[abc]表示匹配 abc 中任何一个,而比如 [A-Za-z] 这种表示也是许可的。此外还有 [^...] 表示除了... 外的字符
3. 选择符 ...|... 二选一
4. 对特殊字符的转义
如 "python\.org" 可以匹配 "python.org" 而不匹配 "pythonAorg"
5. 子模式
对一部分字符串加小括号以进行不同于整串的操作,比如 "P(ython|erl)" 同时匹配 "Python" 和 "Perl"
6. 可选项
(...)? 表示不管带不带这个子模式都会匹配,只识别问号前一个的字符 or 子模式
7. 可重复(也都是识别标识符前一个的字符 or 子模式)
(...)* 重复任意次(也可不重复)
(...)+ 重复至少一次
(...){m[,n]} 重复 m(到 n)次
8. 字符串开头和结尾
'^...'表示从开头开始匹配,注意区别这个和反向匹配多字符(那个有中括号)
'...$'表示只在结尾匹配
9. 一些预定义字符
\d 相当于 [0-9] 所有数字字符
\D 相当于 [^0-9] 所有非数字字符
\s 相当于 [\t\r\n...] 所有空白字符
\S 相当于 所有非空白字符
\w 相当于 [a-zA-Z0-9_] 所有在单词中可能用到的字符(大小写字母,数字,下划线)
\W 相当于 [^\w] 所有非单词书写字符
■re 模块的一些方法
compile(pattern)
根据正则表达式 pattern 返回一个相应的模式对象,用这个对象可以调用其他所有 re 模块下的方法使得使用起来更加方便, 比如原来要 re.search(pattern,string), 现在只要 pattern.search(string)
search(pattern,string) 或 pattern.search(string) 下同,不再复述
从字符串中寻找相关 pattern, 找到则返回一个 object(可以视为 True),没找到则返回 None(可以视为 False)
match(pattern,string)
从字符串开头开始匹配,若成功匹配,返回 object, 否则返回 None // 如果是 match 的 pattern 里有...$ 这种匹配字符串尾的怎么办。。这种矛盾怎么解决,该听谁的?
split(pattern,string)
用 string 中任何与 pattern 匹配的部分作为分隔符分隔 string,返回的是一个列表
findall(pattern,string)
找出 string 中所有和 pattern 匹配的部分,并将其组成一个列表返回
sub(pattern,replace,string)
将 string 中所有 pattern 匹配的部分用 replace 串替换,string 本身值不变,sub 方法返回更改的字符串
replace 中可以带 \g<1>,\g<2>.. 等参数,用来表示 pattern 中的相应的 group。相当于是把原来字符串里匹配到一些 group 的内容动态地提取出来并把 其整合到 replace 里面
如:
- originStr = "Hello, Frank"
- pattern = "Hello, (\w+)"
- replace = "Mein Name ist \g<1>"
- replacedStr = re.sub(pattern,replace,originStr)
- #得到relacedStr是"Mein Name ist Frank"
escape(string)
用于把 stirng 中所有实义字符(在正则表达式引擎的层面上)反转义为带'\'的形式
比如 escape('www.baidu.com') ==> 'www\.baidu\.com' 这样把这个字符串去当 pattern 时就不会有把 "." 当成是通配符了
■匹配对象和组
之前提到了,像 search 这种方法会返回一个 object, 这个 object 是个 MatchedObject, 即匹配对象。那么这个对象中有哪些信息呢
首先要提一下 group 的概念。在一个 pattern 中,常会出现小括号括起来的子模式,根据这些子模式和总模式的关系,可以将 pattern 以及最终匹配出来的字符串分成若干 group
比如 pattern 这样的话:"I (am (Kazuya) Takanashi). This (is) a test" 这里面有四个 group
0: 整个字符串
1:am Kazuya Takanashi
2:Kazuya
3:is
看是第几组只要看左边出现了几个左括号
对于匹配完成后得到的 MatchedObject,它有:
m.group(组号) 获取相应组的内容,若不写组号默认为 0,下同
m.start(组号) 获取相应组在原串中的起始位置
m.end(组号) 获取结束位置
m.span(组号) 以元组的形式返回相应组的开始和结束位置
■正则解析过程浅析
这是我自己 YY 出来的,不知道是否准确。
正则表达式的转义也很复杂,其整个过程应该是这样的:
程序编写时的字符串 ==(第一次转义)==> print 时出现的字符 ==(第二次转义,正则引擎的转义)=> 正则对象
要匹配一个逻辑上的反斜杠, 即匹配的字符串要写 "\\"(不能写 r"\",这可能是整个 python 唯一不能用 rXX 来表示的字符串了),pattern 要写 "\\\\" 或 r"\\" (对于那些反斜杠和它之后跟的东西并不组成一个转义字符的情况,写不写 r 都一样,因为 python 看到反斜杠会自动把它 escape 掉,比如 s="a\.b" 在内存中自动是 "a\\.b"。而对于反斜杠和它之后那个字符组合起来可能引起歧义的情况就有差别了,比如 s="a\tb" 和 k=r"a\tb", 内存中两者分别是 "a\tb" 和 "a\\tb",print 出来后前者有个制表符空格,后者则是 a\tb)
可以看到,re.search("\\\\","\\") 是有返回 object 的,说明匹配成功。这就表明其实这个方法不是直接拿 pattern 在内存中的形式(四条杠)和目标在内存中的形式(两条杠)比较,而是拿到前者之后先对它做一个属于系统层面的转义,再对它做一个专属于正则的转义,之后再拿去和经过正则转义的目标对比
#苦想了很久,姑且算找到一个可以自圆其说的说法。。但是具体是不是这样,还有待检验。关于这个转义来转义去的问题,还需要进一步对 python 字符串和正则本身机制的了解学习
■关于贪婪和懒惰
重复匹配符如 *,+ 这些默认都是贪婪的。
所谓贪婪就是说当可以匹配多种可能时,匹配最长的。比如:
pattern = "<.*>" 而 string = "<a>bcd>ef>"时,re 会匹配到"<a>bcd>ef>"而不是"<a>" 或 "<a>bcd>"
向重复匹配符后加上? 可以使其进行懒惰匹配,也就是匹配最短的,如上例中匹配到的应该是 "或"(注意区分这个和可选项匹配的问号:(...)? 表示可有可无的子模式或字符)
来源: http://www.bubuko.com/infodetail-1978008.html