Loading

python 正则表达式使用简介和实用技巧

1. 元字符释义

  • . 代指任意字符
  • ^ 从字符串开始匹配
  • $ 匹配字符串的结尾
  • * 匹配前面挨着的字符,能匹配 0 到无穷次
  • +*,能匹配 1 到无穷次(最少 1 个)
  • ? 匹配前面挨着的字符,匹配 01
  • {} 自定义匹配次数, {1,6} 匹配 16 次, {6} 匹配 6 次(重复匹配前面挨着的字符)
  • [] 匹配中括号中的任意字符, [x,y*] 匹配 xy 或,或 *(括号中无特殊字符),但以下几个除外
    • -[a-z],匹配 az 中的任意字符
    • ^[^a-z],非,匹配不是 az 以外的任意字符
    • \ 转义
  • | 或,如 'a|b' 匹配 'a''b'
  • () 分组,如 '(abc)' 匹配 'abc'
    • (?P<name>\w+) '?P<name>' 为固定格式, name 为对该组进行命名, '\w' 为真正的匹配规则
    • 上面的固定格式可不写,主要便于阅读和读取返回结果
  • \ 转义,有以下功能
    • 将无意义的普通字符变为有意义
      • \d 匹配任何十进制数,即 0-9
      • \D 匹配任何非数字字符,相当于 [^0-9]
      • \s 匹配任何空白字符,相当于 [\t\n\r\f\v]
      • \S 匹配任何非空白字符,相当于 [^\t\n\r\f\v]
      • \w 对于 Unicode (str) 样式:
        匹配 Unicode 词语的字符,包含了可以构成词语的绝大部分字符,也包括数字和下划线。如果设置了 ASCII 标志,就只匹配 [a-zA-Z0-9_]
        对于 8 位(bytes)样式:
        匹配 ASCII 字符中的数字和字母和下划线,就是 [a-zA-Z0-9_]。如果设置了 LOCALE 标记,就匹配当前语言区域的数字和字母和下划线。
      • \W 匹配非单词字符的字符。这与 \w 正相反。如果使用了 ASCII 旗标,这就等价于 [^a-zA-Z0-9_]。如果使用了 LOCALE 旗标,则会匹配当前区域中既非字母数字也非下划线的字符。
      • \b 匹配一个特殊字符边界,如空格, &#
    • 将有意义的元字符变为无意义
      \. \* \^ \$

2. 基本使用


查找所有匹配的内容

>>> re.findall(r'\d', '12+(34*6+2-5*(2-1))')
['1', '2', '3', '4', '6', '2', '5', '2', '1']

查找第一个匹配的内容

>>> m = re.search(r'(\d)', '12+(34*6+2-5*(2-1))')
>>> m.groups()
('1',)

使用分组

分组可以在需要其他规则辅助定位,但是又不想获取这些规则所匹配到的内容时使用。

>>> re.findall(r'(\w+)\.', 'abd. efg. 123sd')
['abd', 'efg']

可以使用 ?P<name> 为分组命名,并通过分组名获取内容:

>>> re.search(r'(?P<wgroup>\w+)\.', 'abd. efg. 123sd').groups('wgroup')
('abd',)

迭代返回匹配的结果

如果匹配的内容太多,可以使用该方法优化内容使用。

>>> re.finditer(r'\d', '12+(34*6+2-5*(2-1))')
<callable_iterator at 0x283dbd4bdf0>

从字符串起始位置开始匹配

>>> re.match(r'h', 'hello')
<re.Match object; span=(0, 1), match='h'>
>>> re.match(r'e', 'hello')  # None

分割字符串

>>> re.split('ab', 'abcd')
['', 'cd']

用括号将分割的标志包裹起来,可以保留分割的内容:

>>> re.split('(ab)', 'abcd')
['', 'ab', 'cd']

替换字符串

>>> re.sub('[a-z]', '-', 'a123b')
'-123-'

指定最大的替换次数:

>>> re.sub('[a-z]', '-', 'a123b', 1)
'-123b'

同时获取替换的次数

>>> re.subn('[a-z]', '-', 'a123b')
('-123-', 2)

替换时引用前面匹配到的内容
使用命名组:

>>> re.sub('(?P<w>[a-z])', '\g<w>-', 'a123b')  # 将 'a' 替换为 'a-', 'b' 替换为 'b-'
'a-123b-'

不使用命名组:

>>> re.sub('([a-z])', '\g<1>-', 'a123b')
'a-123b-'

预编译规则

预编译可以避免每次调用时的编译性能消耗,虽然 re 库也会在内部做缓存,但缓存的数量是有限的,这会导致所传入的表达式不总是能走缓存,使用预编译可以保证只编译一次。

>>> comp = re.compile(r'\d+')
>>> comp.findall('nasa1')  # 编译后的对象可以调用 search, findall 等匹配方法
['1']

3. 常用技巧


多行文本匹配时,匹配每一行的内容

>>> text = """
... this is
... a
... multiple
... line
... text
... .
... """
>>> re.findall('^[al]', text, re.M)  # 匹配以字母 a, l 开始的行首字母
['a', 'l']

使用多个 flags

如果要同时忽略大小写,以及多行模式匹配,可以使用 | 将多个 flag 拼接起来

>>> text = """
... this is
... A
... multiple
... Line
... text
... .
... """
>>> re.findall('^[al]', text, flags=re.M | re.I)
['A', 'L']

匹配中文

>>> re.findall(r'[\u4e00-\u9fa5]', '你好,我是 john')
['你', '好', '我', '是']

或使用双字节字符匹配(可以包含中文标点符号):

>>> re.findall(r'[^\x00-\xff]', '你好,我是 john')
['你', '好', ',', '我', '是']

匹配不包含某个字符串的的内容

>>> re.findall(r'\b((?!abc)\w+)', 'abcdefg123')
[]
>>> re.findall(r'\b((?!abc)\w+)', 'abdefg123')
['abdefg123']

对上述表达式的解释:

  1. \b 匹配单词的开始或结束
  2. ?!<exp> 零宽负向先行断言,只会匹配后缀 <exp> 不存在的位置
  3. \w 匹配字母或数字或下划线或汉字
  4. + 重复一次或更多次
  5. \b((?!abc)\w)+ 匹配由字母或数字或下划线或汉字组成的字串,但字串中不能出现 abc

匹配多个连串的字符(去掉分组优先级)

比如,想匹配以 abc123 开始的内容,但是又不想把 abc123 作为一个分组,可以使用 ?: 去掉分组优先级:

>>> re.findall(r'(?P<wgroup>(?:123|abc)\.)', 'abc. efg. 123.')
['abc.', '123.']

其中 (?:123|abc) 使用了分组的语法,但不会被视为一个分组。


4. 其它实例


匹配可有可无的字符

如 http/https 中的 s

>>> pat = re.compile(r'((?:http|https)://.*?/)')
>>> pat.findall('http://www.zhparks.com/upload/')
['http://www.zhparks.com/']
>>> pat.findall('https://www.zhparks.com/upload/')
['https://www.zhparks.com/']

或使用 * 号:

>>> pat = re.compile(r'(https*://.*?/)')
>>> pat.findall('https://www.zhparks.com/upload/')
['https://www.zhparks.com/']
>>> pat.findall('http://www.zhparks.com/upload/')
['http://www.zhparks.com/']

5. 实用工具

  1. 在线测试正则表达式: Regex Tester and Debugger Online - Javascript, PCRE, PHP

6. 参考

  1. re --- 正则表达式操作 — Python 3.12.3 文档
  2. Python正则表达式操作指南 · 看云
  3. 正则表达式测试字符串是以http://还是https://开头
posted @ 2024-06-06 11:20  kingron  阅读(16)  评论(0编辑  收藏  举报