码迷,mamicode.com
首页 > 其他好文 > 详细

正则表达式

时间:2016-05-23 15:10:58      阅读:216      评论:0      收藏:0      [点我收藏+]

标签:

正则表达式
    正则表达式有强大并且标准化的方法来处理字符串查找、替换以及用复杂模式来解析文本。
    正则表达式的语法比程序代码更紧凑,格式更严格,比用组合调用字符串处理函数的方法更具有可读性。
    还可以在正则表达式中嵌入注释信息,这样就可以使它有自文档化的功能。

    匹配符:
        ^       匹配字符串开始位置。在多行字符串模式匹配每一行的开头。
        $       匹配字符串结束位置。在多行字符串模式匹配每一行的结尾。
        .       匹配除了换行符外的任何字符,在 alternate 模式(re.DOTALL)下它甚至可以匹配换行。
        \A      匹配字符串开头
        \Z      匹配字符串结尾
        \b      匹配一个单词边界。即 \w 与 \W 之间。
        \B      匹配一个非单词边界;相当于类 [^\b]。
        \d      匹配一个数字。
        \D      匹配一个任意的非数字字符。
        \s      匹配任何空白字符;它相当于类  [ \t\n\r\f\v]。
        \S      匹配任何非空白字符;它相当于类 [^ \t\n\r\f\v]。
        \w      匹配任何字母数字字符;它相当于类 [a-zA-Z0-9_]。
        \W      匹配任何非字母数字字符;它相当于类 [^a-zA-Z0-9_]。
        x?      匹配可选的x字符。即是0个或者1个x字符。
        x*      匹配0个或更多的x。
        x+      匹配1个或者更多x。
        x{n,m}  匹配n到m个x,至少n个,不能超过m个。
        (a|b|c) 匹配单独的任意一个a或者b或者c。
        (x)     捕获组,小括号括起来即可,它会记忆它匹配到的字符串。
                可以用 re.search() 返回的匹配对象的 groups()函数来获取到匹配的值。
        \1      记忆组,它表示记住的第一个分组;如果有超过一个的记忆分组,可以使用 \2 和 \3 等等。
                记忆组的内容也要小括号括起来。
        (?iLmsux)          iLmsux的每个字符代表一种匹配模式
            re.I(re.IGNORECASE): 忽略大小写(括号内是完整写法,下同)
            re.M(re.MULTILINE): 多行模式,改变‘^‘和‘$‘的行为(参见上图)
            re.S(re.DOTALL): 点任意匹配模式,改变‘.‘的行为
            re.L(re.LOCALE): 使预定字符类 \w \W \b \B \s \S 取决于当前区域设定
            re.U(re.UNICODE): 使预定字符类 \w \W \b \B \s \S \d \D 取决于unicode定义的字符属性
            re.X(re.VERBOSE): 松散正则表达式模式。这个模式下正则表达式可以是多行,忽略空白字符,并可以加入注释。
        (?:表达式)         无捕获组。与捕获组表现一样,只是没有内容。
        (?P<name>表达式)   命名组。与记忆组一样,只是多了个名称。
        (?P=name)          命名组的逆向引用。
        (?#...)            “#”后面的将会作为注释而忽略掉。例如:“ab(?#comment)cd”匹配“abcd”
        (?=...)            之后的字符串需要匹配表达式才能成功匹配。不消耗字符串内容。 例:“a(?=\d)”匹配“a12”中的“a”
        (?!...)            之后的字符串需要不匹配表达式才能成功匹配。不消耗字符串内容。 例:“a(?!\d)”匹配“abc”中的“a”
        (?<=...)           之前的字符串需要匹配表达式才能成功匹配。不消耗字符串内容。 例:“(?<=\d)a”匹配“2a”中的“a”
        (?<!...)           之前的字符串需要不匹配表达式才能成功匹配。不消耗字符串内容。 例:“(?<!\d)a”匹配“sa”中的“a”
                           注:上面4个表达式的里面匹配的内容只能是一个字符,多个则报错。
        (?(id/name)yes-pattern|no-pattern)  如果编号为 id 或者别名为 name 的组匹配到字符串,则需要匹配yes-pattern,否则需要匹配no-pattern。 “|no-pattern”可以省略。如:“(\d)ab(?(1)\d|c)”匹配到“1ab2”和“abc”

    元字符:
        "[" 和 "]"
            它们常用来匹配一个字符集。字符可以单个列出,也可以用“-”号分隔的两个给定字符来表示一个字符区间。
                例如,[abc] 将匹配"a", "b", 或 "c"中的任意一个字符;也可以用区间[a-c]来表示同一字符集,和前者效果一致。
            元字符在类别里并不起作用。例如,[a$]将匹配字符"a" 或 "$" 中的任意一个;"$" 在这里恢复成普通字符。
            也可以用补集来匹配不在区间范围内的字符。其做法是把"^"作为类别的首个字符;其它地方的"^"只会简单匹配 "^"字符本身。
                例如,[^5] 将匹配除 "5" 之外的任意字符。
            特殊字符都可以包含在一个字符类中。如,[\s,.]字符类将匹配任何空白字符或","或"."。
        反斜杠 "\"。
            做为 Python 中的字符串字母,反斜杠后面可以加不同的字符以表示不同特殊意义。
            它也可以用于取消所有的元字符,这样你就可以在模式中匹配它们了。
                例如,需要匹配字符 "[" 或 "\",可以在它们之前用反斜杠来取消它们的特殊意义: \[ 或 \\。

    建议使用原始字符串:
        建议在处理正则表达式的时候总是使用原始字符串。如: r‘\bROAD$‘, 而不要写成 ‘\\bROAD$‘
        否则,会因为理解正则表达式而消耗大量时间(正则表达式本身就已经够让人困惑的了)。

    无捕获组:
        有时你想用一个组去收集正则表达式的一部分,但又对组的内容不感兴趣。你可以用一个无捕获组“(?:...)”来实现这项功能。
        除了捕获匹配组的内容之外,无捕获组与捕获组表现完全一样;可以在其中放置任何字符、匹配符,可以在其他组(无捕获组与捕获组)中嵌套它。
        无捕获组对于修改已有组尤其有用,因为可以不用改变所有其他组号的情况下添加一个新组。
        捕获组和无捕获组在搜索效率方面也一样。

    命名组:
        与用数字指定组不同的是,它可以用名字来指定。除了该组有个名字之外,命名组也同捕获组是相同的。
        (?P<name>...) 定义一个命名组,(?P=name) 则是对命名组的逆向引用。
        MatchObject 的方法处理捕获组时接受的要么是表示组号的整数,要么是包含组名的字符串。所以命名组可以通过数字或者名称两种方式来得到一个组的信息。

    松散正则表达式:
        为了方便阅读和维护,可以使用松散正则表达式,它与普通紧凑的正则表达式有两点不同:
        1, 空白符被忽略。空格、制表符(tab)和回车会被忽略。如果需要匹配他们,可以在前面加一个“\”来转义。
        2, 注释被忽略。注释以“#”开头直到行尾,与python代码中的一样。
        使用松散正则表达式,需要传递一个叫 re.VERBOSE的 参数。详细见下面例子。

    例如:

        # 必须引入 re 标准库
        import re

        # 字符串替换:  sub() 与 subn()
        s = ‘100 NORTH MAIN ROAD‘
        # 将字符串结尾的单词“ROAD”替换成“RD.”;该 re.sub() 函数执行基于正则表达式的字符串替换。
        print(re.sub(r‘\bROAD$‘, ‘RD.‘, s)) # 打印: 100 NORTH MAIN RD.
        ## subn() 与 sub() 作用一样,但返回的是包含新字符串和替换执行次数的两元组。
        print(re.subn(r‘\bROAD$‘, ‘RD.‘, s)) # 打印: (‘100 NORTH MAIN RD.‘, 1)

        # 字符串分割, split()
        # 在正则表达式匹配的地方将字符串分片,将返回列表。只支持空白符和固定字符串。可指定最大分割次数,不指定将全部分割。
        print(re.split(r‘\s+‘, ‘this is a test‘)) # 打印: [‘this‘, ‘is‘, ‘a‘, ‘test‘]
        print(re.split(r‘\W+‘, ‘This is a test.‘, 2)) # 指定分割次数,打印:[‘this‘, ‘is‘, ‘a test‘]
        # 如果你不仅对定界符之间的文本感兴趣,也需要知道定界符是什么。在 RE 中使用捕获括号,就会同时传回他们的值。
        print(re.split(r‘(\W+)‘, ‘This is a test.‘, 2)) # 捕获定界符,打印:[‘this‘, ‘ ‘, ‘is‘, ‘ ‘, ‘a test‘]

        ## `MatchObject` 实例的几个方法
        r = re.search(r‘\bR(OA)(D)\b‘, s)
        print(r.groups()) # 返回一个包含字符串的元组,可用下标取元组的内容,打印: (‘OA‘, ‘D‘)
        print(r.group())  # 返回正则表达式匹配的字符串,打印: ROAD
        print(r.group(2)) # 返回捕获组对应的内容(用数字指明第几个捕获组),打印: D
        print(r.start())  # 返回匹配字符串开始的索引, 打印: 15
        print(r.end())    # 返回匹配字符串结束的索引,打印: 19
        print(r.span())   # 返回一个元组包含匹配字符串 (开始,结束) 的索引,打印: (15, 19)

        # 匹配多个内容, findall() 返回一个匹配字符串行表
        p = re.compile(‘\d+‘)
        s0 = ‘12 drummers drumming, 11 pipers piping, 10 lords a-leaping‘
        print(p.findall(s0)) # 打印: [12, 11, 10]
        print(re.findall(r‘\d+‘, s0)) # 也可这样写,打印: [12, 11, 10]

        # 匹配多个内容, finditer() 以迭代器返回
        iterator = p.finditer(s0)
        # iterator = re.finditer(r‘\d+‘, s0) # 上句也可以这样写
        for match in iterator:
            print(match.group()) # 三次分别打印:12、 11、 10

        # 记忆组
        print(re.sub(‘([^aeiou])y$‘, ‘ies‘, ‘vacancy‘))    # 将匹配的最后两个字母替换掉,打印: vacanies
        print(re.sub(‘([^aeiou])y$‘, r‘\1ies‘, ‘vacancy‘)) # 将匹配的最后一个字母替换掉,记忆住前一个(小括号那部分),打印: vacancies
        print(re.search(‘([^aeiou])y$‘, ‘vacancy‘).group(1)) # 使用 group() 函数获取对应的记忆组内容,打印: c

        # 记忆组(匹配重复字符串)
        p = re.compile(r‘(?P<word>\b\w+)\s+\1‘) # 注意, re.match() 函数不能这样用,会返回 None
        p = p.search(‘Paris in the the spring‘)
        # p = re.search(r‘(?P<word>\b\w+)\s+\1‘, ‘Paris in the the spring‘) # 这一句可以替换上面两句
        print(p.group())  # 返回正则表达式匹配的所有内容,打印: the the
        print(p.groups()) # 返回一个包含字符串的元组,打印: (‘the‘,)

        # 捕获组
        r = re.search(r‘\bR(OA)(D)\b‘, s) # 如过能匹配到,返回一个 SRE_Match 类(正则表达式匹配对象);匹配不到则返回“None”
        # `MatchObject` 实例的几个方法
        if r: # 如果匹配不到,则 r 为 None,直接执行下面语句则会报错;这里先判断一下,避免这错误
            print(r.groups()) # 返回一个包含字符串的元组,可用下标取元组的内容,打印: (‘OA‘, ‘D‘)
            print(r.group())  # 返回正则表达式匹配的字符串,打印: ROAD
            print(r.group(2)) # 返回捕获组对应的内容(用数字指明第几个捕获组),打印: D

        # 无捕获组
        print(re.match("([abc])+", "abcdefab").groups())   # 正常捕获的结果: (‘c‘,)
        print(re.match("(?:[abc])+", "abcdefab").groups()) # 无捕获组的结果: ()

        # 命名组
        m = re.match(r‘(?P<word>\b\w+\b) *(?P<word2>\b\w+\b)‘, ‘Lots of punctuation‘)
        print(m.groups())       # 返回正则表达式匹配的所有内容,打印:(‘Lots‘, ‘of‘)
        print(m.group(1))       # 通过数字得到对应组的信息,打印: Lots
        print(m.group(‘word2‘)) # 通过名称得到对应组的信息,打印: of

        # 命名组 逆向引用
        p = re.compile(r‘(?P<word>\b\w+)\s+(?P=word)‘) # 与记忆组一样用法, re.match() 函数同样不能这样用,会返回 None
        p = p.search(‘Paris in the the spring‘) #  r‘(?P<word>\b\w+)\s+(?P=word)‘ 与 r‘(?P<word>\b\w+)\s+\1‘ 效果一样
        print(p.group())  # 返回正则表达式匹配的所有内容,打印: the the
        print(p.groups()) # 返回一个包含字符串的元组,打印: (‘the‘,)

        # 使用松散正则表达式,以判断罗马数字为例
        pattern = ‘‘‘
            ^                   # beginning of string
            (M{0,3})            # thousands - 0 to 3 Ms
            (CM|CD|D?C{0,3})    # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 Cs),
                                #            or 500-800 (D, followed by 0 to 3 Cs)
            (XC|XL|L?X{0,3})    # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 Xs),
                                #        or 50-80 (L, followed by 0 to 3 Xs)
            (IX|IV|V?I{0,3})    # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 Is),
                                #        or 5-8 (V, followed by 0 to 3 Is)
            $                   # end of string
            ‘‘‘
        print(re.search(pattern, ‘M‘)) # 这个没有申明为松散正则表达式,按普通的来处理了,打印: None
        print(re.search(pattern, ‘M‘, re.VERBOSE).groups()) # 打印: (‘M‘, ‘‘, ‘‘, ‘‘)

        # (?iLmsux) 用法
        # 以下这三句的写法都是一样的效果,表示忽略大小写,打印: [‘aa‘, ‘AA‘]
        print(re.findall(r‘(?i)(aa)‘, ‘aa kkAAK s‘))
        print(re.findall(r‘(aa)‘, ‘aa kkAAK s‘, re.I))
        print(re.findall(r‘(aa)‘, ‘aa kkAAK s‘, re.IGNORECASE))
        # 可以多种模式同时生效
        print(re.findall(r‘(?im)(aa)‘, ‘aa kkAAK s‘))  # 直接在正则表达式里面写
        print(re.findall(r‘(aa)‘, ‘aa kkAAK s‘, re.I | re.M)) # 在参数里面写
        print(re.findall(r‘(aa)‘, ‘aa kkAAK s‘, re.I or re.M))

        # 预编译正则表达式解析的写法
        # romPattern = re.compile(pattern)  # 如果不是松散正则表达式,则这样写,即少写 re.VERBOSE 参数
        romPattern = re.compile(pattern, re.VERBOSE)
        print(romPattern.search(‘MCMLXXXIX‘).groups()) # 打印: (‘M‘, ‘CM‘, ‘LXXX‘, ‘IX‘)
        print(romPattern.search(‘MMMDCCCLXXXVIII‘).groups()) # 打印: (‘MMM‘, ‘DCCC‘, ‘LXXX‘, ‘VIII‘)
        # match()、search()、sub()、findall() 等等都可以这样用

    match() vs search()
        match() 函数只检查 RE 是否在字符串开始处匹配,而 search() 则是扫描整个字符串。记住这一区别是重要的。
        match() 只报告一次成功的匹配,它将从 0 处开始;如果匹配不是从 0 开始的, match() 将不会报告它。
        search() 将扫描整个字符串,并报告它找到的第一个匹配。
    例:
        print(re.match(‘super‘, ‘superstition‘).span())  # 打印: (0, 5)
        print(re.match(‘super‘, ‘insuperable‘))          # 打印: None
        print(re.search(‘super‘, ‘superstition‘).span()) # 打印: (0, 5)
        print(re.search(‘super‘, ‘insuperable‘).span())  # 打印: (2, 7)

正则表达式

标签:

原文地址:http://blog.csdn.net/lyj1101066558/article/details/51479665

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!