2017-08-21 10:36:06

python正则表达式一些细节

我学过很多次正则表达式,每次都只是在网络上随便找找文章看看,一些文章要么说的浅显,要么有些细节没有提到,所以对于正则我一直处于一知半解的程度。
比如正/反向前/后视断言、扩展表示法、贪婪匹配等
这次我通读了python关于正则表达式的官方文档,将一些细节记录下来。

所以此文不是用来给想学python正则表达式基础的人看的,而是给已经了解基础甚至写过一定正则代码的人看的

表达式细节

  • 要搜索的的字符串可以是unicode字符串和8-bit的byte字符串,但是不能混合
  • 特殊的字符在'[]'会失去他们的特殊意义:比如:[(+)]会匹配任何字面上的字符:'[' '(' '+' '' ')'
  • 如果python的^不是[]的首个字符,那么它没有任何意义
  • 要在[]中匹配']',必须用']'反转,或者将']'放在'[]'的开头
  • 对于|来说,它永远是非贪婪匹配,且是从左向右匹配的,如果左边的匹配到了,那么它不会管右边的了。要匹配|那么需要使用\|,或者使用[|]
  • 对于()来说,要匹配(),或者用[(] [)]

贪婪匹配细节

  • '*' '+' '?'默认是贪婪匹配,在这些贪婪匹配的限定词后加上'?'表示非贪婪匹配
  • {m,n}的非贪婪匹配:对于'aaaaa',a{3,5}? 匹配'aaa'
  • 模式匹配使用分组操作符时,正则表达式引擎将试图“吸收”匹配该模式的尽可能多的字符。这通常被叫做贪婪匹配。问号要求正则表达式引擎去“偷懒”,如果可能,就在当前的正则表达式中尽可能少地匹配字符,留下尽可能多的字符给后面的模式(如果存在)。
  • 重复限定词(*, +, ?, {m,n}等等)不能直接嵌套,这样恰好避免了非贪婪匹配限定词:?,但是可以通过括号来实现嵌套:

    (?:a{6})* # 匹配任意多个6个'a'

扩展表示法

  • (?...) 一般不会创建一个分组,但是(?P<name>...)是一个例外
  • (?aiLmsux) 在正则表达式中嵌入一个或者多个特殊“标记” 参数(或者通过函数/方法)

    • a,只匹配ASCII字符,对应的python标志:re.A、re.ASCII
    • i,不区分大小写,对应的python标志:re.I、 re.IGNORECASE
    • L,根据所使用的本地语言环境通过\w、 \W、 \b、 \B、 \s、 \S 实现匹配,对应的python标志:re.L、 re.LOCALE
    • m,^和$分别匹配目标字符串中行的起始和结尾,而不是严格匹配整个字符串本身的起始和结尾,对应的python标志:re.M、 re.MULTILINE
    • s,“.”(点号)通常匹配除了\n(换行符)之外的所有单个字符;该标记表示“.”(点号)能够匹配全部字符,对应的python标志:re.S、 rer.DOTALL
    • x,通过反斜线转义, 否则所有空格加上#(以及在该行中所有后续文字)都被忽略,除非
    • 在一个字符类中或者允许注释并且提高可读性,对应的python标志:re.X、 re.VERBOSE
  • (?imsx-imsx:...) 设置或去除响应的标志

  • (?P=name),一个命名组的反向引用,它表达的是之前已命名的命名组,比如<(?P<tag>[A-Z][A-Z0-9]*)\b[^>]*>.*?</(?P=tag)>.,其中的(?P=tag)就代表([A-Z][A-Z0-9]*),它对应的是数字分组的'(\w)\1'其中\1表示(\w)只不过命名组的引用更清晰明了
  • (?:\w+\.)*:以句点作为结尾的字符串,例如“google.”、“twitter.”、“facebook.”,但是这些匹配不会保存下来供后续的使用和数据检索
  • (?#comment):此处并不做匹配,只是作为注释
  • (?=.com):正向前视断言,如果一个字符串后面跟着“.com”才做匹配操作,并不使用任何目标字符串,比如对于Isaac(?!Asimov)来说,当且仅当Isaac后面紧跟着Asimov时才会匹配成功
  • (?!.net):反向前视断言,如果一个字符串后面不是跟着“.net”才做匹配操作,比如对于Isaac(?!Asimov)来说,当且仅当Isaac后面没有紧跟着Asimov时才会匹配成功
  • (?<=800-):正向后视断言,如果字符串之前为“800-”才做匹配,假定为电话号码, 同样,并不使用任何输入字符串
  • (?<!192\.168\.):反向后视断言,如果一个字符串之前不是“192.168.”才做匹配操作,假定用于过滤掉一组 C 类 IP 地址
  • (?(id/name)yes-pattern|no-pattern):如果数字或命名分组存在,那么会尝试匹配yes-pattern,否则尝试匹配no-pattern
  • (?(1)y|x):如果一个匹配组 1(\1)存在, 就与 y 匹配; 否则, 就与 x 匹配

限定词细节

  • \number,匹配的是数字分组,有效数字是1-99,如果不在这个范围,会认为是一个八进制数字表示的字符,在[]中的\number会被认为是字符串
  • \A 匹配字符串的开始
  • \b 匹配任何单词边界,\b\w\W的边界,一个单词有字符、数字、下划线组成,所以单词边界的意思很明显了,所以所有不是字符、数字、下划线的都能匹配\b,比如r'\bfoo\b'会匹配foo,foo.,(foo),bar foo baz但是不匹配foobarfoo3,但是这些可以被ASCII标志改变
  • \B 是\b的对立面,r'py\B'会匹配'python', 'py3', 'py2'但是不匹配'py', 'py.', 或者 'py!',它也会被ASCII标记影响
  • \w 等同于[a-zA-Z0-9_]
  • \Z 匹配末尾
  • \d 如果是bytes模式则匹配[0-9],如果是unicode字符串模式,那么匹配[0-9](如果unicode字符串模式下,并且指定了ASCII标记,那么只会匹配[0-9]
  • \s 一般指的是[ \t\n\r\f\v],但是在unicode字符串模式匹配下,还会匹配其他的(当然如果使用ASCII标记,那么只会匹配[ \t\n\r\f\v]),如果在bytes模式下,那么只会匹配[ \t\n\r\f\v]

Permanent link of this article:http://nulls.cc/post/python_regex_detail

-- EOF --