正则表达式,用于在一大堆数据中查找信息,学习后有利于爬虫信息抓取。
“. ^ $ * + ? { } [ ] \ | ( )”是元字符(关键字),如要匹配原字符则需加“\”,如“\[”“\\”。为避免与转义符(\n、\b)冲突,可在字符串前加r,即 r"" 或 r'' 。
字符:
“\d”表示数字
“\D”表示非数字的字符
“\s”表示空白字符,相当于[ \t\n\r\f\v]
“\S”相当于[^ \t\n\r\f\v]
“\w”表示数字或字母
“\W”表示非数字和字母的字符
“.”表示除换行符'\n'外的所有字符,DOTALL模式下可匹配任何字符(包括'\n')
“[]”整体为一个字符,其中的内容表示"或者"关系,同时元字符全部失效。如:[12]表示'1'或'2',[a-z]表示小写字母(包括扩展拉丁字母如 'é'),[A-Za-z]表示所有字母,而[^a]表示除'a'以外的所有字符,[a^]表示'a'或'^'。由于元字符失效,从而可以 '[\n]' 的方式表示回车符等转义符,但复杂情况下仍推荐使用 r""。
以下字符都不代表实际字符,即所谓零宽度,称为断言:
“^”指示行的开头,不代表实际字符,如MULTILINE模式下以“^a”去匹配“b\nab”则span=(2, 3)。若不是MULTILINE,则仅指示字符串开头。
“$”指示行的末尾。同样需要MULTILINE
“\A”指示字符串的开头
“\Z”指示字符串的末尾
“\b”指示词边界,即每个单词的开头和结尾,单词结构中可包括数字和字母,其他字符如空格逗号可以将其分割为一个个单词。可以指示字符串开头。可能与退格符'\b'冲突,加r或使用'\\b'。
“\B”指示不在词边界时才匹配
“|”表示或者,优先级比普通字符还低,如“phone|tele”表示"phone"或"tele"
“()”可控制“|”的范围,如“the (phone|tele)”
重复:
“*”表示前一个字符重复0~+inf次
“+”表示前一个字符重复1~+inf次
“?”表示前一个字符重复0或1次,可有可无
“{a, b}”表示前一个字符重复a~b次,“{, b}”表示0~b,“{a, }”表示a~+inf次。
以上符号默认均为贪婪模式,即匹配尽可能多的字符。如果需匹配尽可能少的字符,可在其后加上“?”符号,如“a*?”为非贪婪模式。
“()”可使重复符号作用于其括住的全部字符上,如“(br)*”指'br'重复0~+inf次
【re模块】
基本方法:
“p = re.compile(r'ab*')”编译一个匹配器(正则),r'ab*'为匹配规则的表达式(模式)
“m = p.match('abbcabd')”在'abbcabd'中从第一个字符开始匹配,结果保存在match对象中并返回
“m = p.search('abbcabd')”在'abbcabd'中不断向后查找,只返回第一个最先匹配到的内容
“listAll = p.findall('abbcabd')”在'abbcabd'中不断向后查找所有能匹配的内容,并将其以列表的方式返回
“iterAll = p.finditer('abbcabd')”上一种方式的迭代器版本,迭代时才查找并返回内容
“s = m.group()”或“s = m.group(0)”获得匹配的内容
“s = m.start()”获得匹配内容在字符串中的起始索引值
“s = m.end()”获得匹配内容在字符串中的终止索引值
“s = m.span()”获得匹配内容在字符串中的范围,元组方式返回
“print(m)”输出匹配的范围和内容
分组:
在正则表达式中把需要的信息用小括号“()”括起来,即可获得它们,称为分组。如:
“p = re.compile(r'\w(\w)(\w+)')”
“m = p.match('This is Python')”
之后“m.group(1)”可返回第一个分组的内容,即'h'
“m.group(2)”可返回第二个分组的内容,即'is'
以此类推
而“m.group()”或“m.group(0)”依然返回匹配到的所有内容,即 'This'
“m.groups()”可将所有分组内容以元组的方式返回
分组编号从左到右,由内而外。如以r'\w((\w)\w+)'匹配'This is Python'则第一个分组内容为 'his',第二个为 'h',groups()得 ('his', 'h')。
注意分组后findall和finditer只返回分组的内容,若有多个分组则将每次匹配到的各分组内容以元组的方式存储在列表中。
“\1”可指代前面第一个分组匹配到的内容,表示“\1”这里必须要再次出现此内容,可用于检测双字(叠词)。如:
p = re.compile(r'\b(\w+)\s+\1\b')
print(p.search('Paris in the the spring').group())
得:'the the'。
更多分组:
“(?: ... )”中 ' ... ' 处输入的表达式不会被groups()捕获。可用于不重要信息的重复如 r'(?:the\s?)*'。称为非捕获组
“(?P<gr>...)”可将此分组命名为 'gr' ,之后通过“grou('gr')”可获得此分组的内容。称为命名组
同时“(?P=gr)”可指代前面分组名为 'gr' 匹配到的内容,表示“(?P=gr)”这里必须要再次出现此内容。
以上两种表达式的“P”指Python特有。
“m.groupdict()”可返回所有被命名的分组内容,分组名为键(key),分组内容为值(value)
前向断言:
“(?=…)”指此处应出现表达式 '...' 所描述的内容,如无则此次匹配失败。匹配成功后,其自身不计入匹配内容,原因是其自身不代表实际字符,即零宽度。这被称为前向肯定断言。如字符串 "What's that?",若以 r"What's(?=\sth)" 匹配之则得 "What's",若以 r"What's(?=\sth)\s\w+[?]$" 匹配之则得 "What's that?"。
“(?!…)”与上一种相反,指此处不应出现表达式 '...' 所描述的内容,如出现则此次匹配失败。这被称为前向否定断言。可用于排除某种文件后缀,如 r'.*[.](?!bat$)[^.]*$' 只可匹配后缀为"bat"
标志:
可以在re.compile()中增加匹配标志的参数,相当于对匹配方式进行设置。标志可以叠加,在其之间需加上 '|' 按位与运算符,如:“p.compile(r'ab*, re.M|re.I)”
“re.M”设置MULTILINE模式(多行匹配模式),使 '^' 指示行的开头, '$' 指示行的末尾。也可写为“re.MULTILINE”
“re.I”设置IGNORECASE模式,忽略大小写,即大写既可匹配大写也可匹配小写,小写既可匹配小写也可匹配大写。也可写为“re.IGNORECASE”
“re.L”设置LOCALE模式,方便处理本地所使用的拉丁语言。比如 'é' 'ñ' 'ç' 对于西班牙语而言只有 'é' 'ñ' 是字母,但对于法语而言则只有 'é' 'ç' 是字母。未设置re.L时,Python3默认进行 Unicode 匹配,即将 'é' 'ñ' 'ç' 都识别为字母。设置后,则据地区而定。主要影响 '\w' '\W' '\b' '\B' 和大小写忽略(re.I)。也可写为“re.LOCALE”
“re.S”设置DOTALL模式,使 '.' 可匹配任何字符,包括 '\n'。也可写为“re.DOTALL”
“re.A”设置ASCII模式,使默认的 Unicode 匹配变为 ASCII 匹配,影响 '\w' '\W' '\b' '\B' '\s' '\S' 的工作。也可写为“re.ASCII”
“re.X”设置VERBOSE模式,可使正则表达式更易读。设置re.X后,表达式中所有空格都将被忽略,并且允许加入注释,指示各部分的含义,也可写为“re.VERBOSE”,如:
charref = re.compile(r"""
&[#] # Start of a numeric entity reference
(
0[0-7]+ # Octal form
| [0-9]+ # Decimal form
| x[0-9a-fA-F]+ # Hexadecimal form
)
; # Trailing semicolon
""", re.VERBOSE)
若未设置re.X则写为:
charref = re.compile("&#(0[0-7]+"
"|[0-9]+"
"|x[0-9a-fA-F]+);")
设置后空格需以 r'\ ' 表示。
模块级函数:
可以不编译匹配器(正则)而直接使用相应函数匹配内容,如:
“m = match(r'ab*', 'abbcabd', re.M)”
“m = search(r'ab*', 'abbcabd', re.M)”
“listAll = findall(r'ab*', 'abbcabd', re.M)”
“iterAll = finditer(r'ab*', 'abbcabd', re.M)”
都将表达式放在第一个参数、字符串在第二个参数、标志在第三个参数即可。
正则表达式用于处理字符串的re函数:
“re.split()”可以以正则表达式匹配的内容为分割符,分割字符串。
如:
“p = re.compile(r'\W+')”
“listS = p.split("This is short and sweet.")”
结果为:['This', 'is', 'short', 'and', 'sweet', '']
可指定其最大分割次数,如:
“p.split("This is short and sweet.", maxsplit=2)”指split最多分割2两次,
得:['This', 'is', 'short and sweet.']
也可写为“p.split("This is short and sweet.", 2)”
若正则中有捕获分组,则还将返回捕获分组的内容,如:
“p2 = re.compile(r'(\W+)')”
“listS2 = p2.split("This is short and sweet.")”
结果为:['This', ' ', 'is', ' ', 'short', ' ', 'and', ' ', 'sweet', '.', '']
“re.sub()”可将正则在字符串中匹配到的内容替换为另一个内容。
如:
“p = re.compile('(blue|white|red)')”
“s = p.sub('colour', 'blue socks and red shoes')”
结果为:'colour socks and colour shoes'
sub()同样可指定最大替换次数,如:
“p.sub('colour', 'blue socks and red shoes', count=1)”指sub最多替换1次,
得:'colour socks and red shoes'
也可写为“p.sub('colour', 'blue socks and red shoes', 1)”
所替换成的另一个内容中可引用匹配内容中的分组内容,可写为 '\1' 或 '\g<1>' ,表示引用第一个分组。对于命名组 '(?P<name>...)' 还可写为 '\g<name>' ,如:
“p = re.compile('section{ (?P<name> [^}]* ) }', re.X)”
“p.sub(r'subsection{\1}','section{First}')”
“p.sub(r'subsection{\g<1>}','section{First}')”
“p.sub(r'subsection{\g<name>}','section{First}')”
结果均为:'subsection{First}'还可为sub()传入一个函数,sub()会将匹配到的每一个内容以match对象的方式,传入函数中,然后将匹配的内容替换为函数的返回值。如:
“p = re.compile(r'\d+')”
“p.sub(func, 'Call 65490 for printing, 49152 for user code.')”
可依次将匹配到的 '65490'、'49152' 作为 match 对象,传入 func 函数。
若 func = lambda m: hex(int(m.group())) ,则得:
'Call 0xffd2 for printing, 0xc000 for user code.'
此方法可将字符串中的各个整数替换为16进制数
“subn()”的用法与sub()完全相同,但还会返回替换次数,如:
“p = re.compile('(blue|white|red)')”
“s = p.subn('colour', 'blue socks and red shoes')”
结果为:('colour socks and colour shoes', 2)
更多方法/函数:
“re.fullmatch()”用法与re.match()一样,但要求正则与字符串必须从头到尾完全匹配,否则返回None。相当于在正则末尾加了一个 '\Z'
building...
参考:正则表达式HOWTO — Python 3.10.2 文档