精华内容
下载资源
问答
  • python正则表达式详解
    2021-01-29 05:49:21

    正则表达式是一个很强大的字符串处理工具,几乎任何关于字符串的操作都可以使用正则表达式来完成,作为一个爬虫工作者,每天和字符串打交道,正则表达式更是不可或缺的技能,正则表达式的在不同的语言中使用方式可能不一样,不过只要学会了任意一门语言的正则表达式用法,其他语言中大部分也只是换了个函数的名称而已,本质都是一样的。下面,我来介绍一下python中的正则表达式是怎么使用的。

    首先,python中的正则表达式大致分为以下几部分:

    元字符

    模式

    函数

    re 内置对象用法

    分组用法

    环视用法

    所有关于正则表达式的操作都使用 python 标准库中的 re 模块。

    一、元字符 (参见 python 模块 re 文档)

    .                    匹配任意字符(不包括换行符)

    ^                    匹配开始位置,多行模式下匹配每一行的开始

    $                    匹配结束位置,多行模式下匹配每一行的结束

    *                    匹配前一个元字符0到多次

    +                    匹配前一个元字符1到多次

    ?                    匹配前一个元字符0到1次

    {m,n}                匹配前一个元字符m到n次

    \\                   转义字符,跟在其后的字符将失去作为特殊元字符的含义,例如\\.只能匹配.,不能再匹配任意字符

    []                   字符集,一个字符的集合,可匹配其中任意一个字符

    |                    逻辑表达式 或 ,比如 a|b 代表可匹配 a 或者 b

    (...)                分组,默认为捕获,即被分组的内容可以被单独取出,默认每个分组有个索引,从 1 开始,按照"("的顺序决定索引值

    (?iLmsux)            分组中可以设置模式,iLmsux之中的每个字符代表一个模式,用法参见 模式 I

    (?:...)              分组的不捕获模式,计算索引时会跳过这个分组

    (?P...)        分组的命名模式,取此分组中的内容时可以使用索引也可以使用name

    (?P=name)            分组的引用模式,可在同一个正则表达式用引用前面命名过的正则

    (?#...)              注释,不影响正则表达式其它部分,用法参见 模式 I

    (?=...)              顺序肯定环视,表示所在位置右侧能够匹配括号内正则

    (?!...)              顺序否定环视,表示所在位置右侧不能匹配括号内正则

    (?<=...)             逆序肯定环视,表示所在位置左侧能够匹配括号内正则

    (?

    (?(id/name)yes|no)   若前面指定id或name的分区匹配成功则执行yes处的正则,否则执行no处的正则

    \number              匹配和前面索引为number的分组捕获到的内容一样的字符串

    \A                   匹配字符串开始位置,忽略多行模式

    \Z                   匹配字符串结束位置,忽略多行模式

    \b                   匹配位于单词开始或结束位置的空字符串

    \B                   匹配不位于单词开始或结束位置的空字符串

    \d                   匹配一个数字, 相当于 [0-9]

    \D                   匹配非数字,相当于 [^0-9]

    \s                   匹配任意空白字符, 相当于 [ \t\n\r\f\v]

    \S                   匹配非空白字符,相当于 [^ \t\n\r\f\v]

    \w                   匹配数字、字母、下划线中任意一个字符, 相当于 [a-zA-Z0-9_]

    \W                   匹配非数字、字母、下划线中的任意字符,相当于 [^a-zA-Z0-9_]

    二、模式

    I    IGNORECASE, 忽略大小写的匹配模式, 样例如下

    s = 'hello World!'

    regex = re.compile("hello world!", re.I)

    print regex.match(s).group()

    #output> 'Hello World!'

    #在正则表达式中指定模式以及注释

    regex = re.compile("(?#注释)(?i)hello world!")

    print regex.match(s).group()

    #output> 'Hello World!'

    L    LOCALE, 字符集本地化。这个功能是为了支持多语言版本的字符集使用环境的,比如在转义符\w,在英文环境下,它代表[a-zA-Z0-9_],即所以英文字符和数字。如果在一个法语环境下使用,缺省设置下,不能匹配"é" 或   "ç"。加上这L选项和就可以匹配了。不过这个对于中文环境似乎没有什么用,它仍然不能匹配中文字符。

    M    MULTILINE,多行模式, 改变 ^ 和 $ 的行为

    s = '''first line

    second line

    third line'''

    # ^

    regex_start = re.compile("^\w+")

    print regex_start.findall(s)

    # output> ['first']

    regex_start_m = re.compile("^\w+", re.M)

    print regex_start_m.findall(s)

    # output> ['first', 'second', 'third']

    #$

    regex_end = re.compile("\w+$")

    print regex_end.findall(s)

    # output> ['line']

    regex_end_m = re.compile("\w+$", re.M)

    print regex_end_m.findall(s)

    # output> ['line', 'line', 'line']

    S   DOTALL,此模式下 '.' 的匹配不受限制,可匹配任何字符,包括换行符

    s = '''first line

    second line

    third line'''

    #

    regex = re.compile(".+")

    print regex.findall(s)

    # output> ['first line', 'second line', 'third line']

    # re.S

    regex_dotall = re.compile(".+", re.S)

    print regex_dotall.findall(s)

    # output> ['first line\nsecond line\nthird line']

    X    VERBOSE,冗余模式, 此模式忽略正则表达式中的空白和#号的注释,例如写一个匹配邮箱的正则表达式

    email_regex = re.compile("[\w+\.]+@[a-zA-Z\d]+\.(com|cn)")

    email_regex = re.compile("""[\w+\.]+ # 匹配@符前的部分

    @ # @符

    [a-zA-Z\d]+ # 邮箱类别

    \.(com|cn) # 邮箱后缀 """, re.X)

    U    UNICODE,使用 \w, \W, \b, \B 这些元字符时将按照 UNICODE 定义的属性.

    正则表达式的模式是可以同时使用多个的,在 python 里面使用按位或运算符 | 同时添加多个模式

    如 re.compile('', re.I|re.M|re.S)

    每个模式在 re 模块中其实就是不同的数字

    print re.I

    # output> 2

    print re.L

    # output> 4

    print re.M

    # output> 8

    print re.S

    # output> 16

    print re.X

    # output> 64

    print re.U

    # output> 32

    三、函数 (参见 python 模块 re 文档)

    python 的 re 模块提供了很多方便的函数使你可以使用正则表达式来操作字符串,每种函数都有它自己的特性和使用场景,熟悉之后对你的工作会有很大帮助

    compile(pattern, flags=0)

    给定一个正则表达式 pattern,指定使用的模式 flags 默认为0 即不使用任何模式,然后会返回一个 SRE_Pattern (参见 第四小节 re 内置对象用法) 对象

    regex = re.compile(".+")

    print regex

    # output> <_sre.sre_pattern object at>

    这个对象可以调用其他函数来完成匹配,一般来说推荐使用 compile 函数预编译出一个正则模式之后再去使用,这样在后面的代码中可以很方便的复用它,当然大部分函数也可以不用 compile 直接使用,具体见 findall 函数

    s = '''first line

    second line

    third line'''

    #

    regex = re.compile(".+")

    # 调用 findall 函数

    print regex.findall(s)

    # output> ['first line', 'second line', 'third line']

    # 调用 search 函数

    print regex.search(s).group()

    # output> first lin

    escape(pattern)

    转义 如果你需要操作的文本中含有正则的元字符,你在写正则的时候需要将元字符加上反斜扛 \ 去匹配自身, 而当这样的字符很多时,写出来的正则表达式就看起来很乱而且写起来也挺麻烦的,这个时候你可以使用这个函数,用法如下

    s = ".+\d123"

    #

    regex_str = re.escape(".+\d123")

    # 查看转义后的字符

    print regex_str

    # output> \.\+\\d123

    # 查看匹配到的结果

    for g in re.findall(regex_str, s):

    print g

    # output> .+\d123

    findall(pattern, string, flags=0)

    参数 pattern 为正则表达式, string 为待操作字符串, flags 为所用模式,函数作用为在待操作字符串中寻找所有匹配正则表达式的字串,返回一个列表,如果没有匹配到任何子串,返回一个空列表。

    s = '''first line

    second line

    third line'''

    # compile 预编译后使用 findall

    regex = re.compile("\w+")

    print regex.findall(s)

    # output> ['first', 'line', 'second', 'line', 'third', 'line']

    # 不使用 compile 直接使用 findall

    print re.findall("\w+", s)

    # output> ['first', 'line', 'second', 'line', 'third', 'line']

    finditer(pattern, string, flags=0)

    参数和作用与 findall 一样,不同之处在于 findall 返回一个列表, finditer 返回一个迭代器(参见 http://www.cnblogs.com/huxi/archive/2011/07/01/2095931.html ), 而且迭代器每次返回的值并不是字符串,而是一个 SRE_Match (参见 第四小节 re 内置对象用法) 对象,这个对象的具体用法见 match 函数。

    s = '''first line

    second line

    third line'''

    regex = re.compile("\w+")

    print regex.finditer(s)

    # output>

    for i in regex.finditer(s):

    print i

    # output> <_sre.sre_match object at>

    # <_sre.sre_match object at>

    # <_sre.sre_match object at>

    # <_sre.sre_match object at>

    # <_sre.sre_match object at>

    # <_sre.sre_match object at>

    match(pattern, string, flags=0)

    使用指定正则去待操作字符串中寻找可以匹配的子串, 返回匹配上的第一个字串,并且不再继续找,需要注意的是 match 函数是从字符串开始处开始查找的,如果开始处不匹配,则不再继续寻找,返回值为 一个 SRE_Match(参见 第四小节 re 内置对象用法) 对象,找不到时返回 None

    s = '''first line

    second line

    third line'''

    # compile

    regex = re.compile("\w+")

    m = regex.match(s)

    print m

    # output> <_sre.sre_match object at>

    print m.group()

    # output> first

    # s 的开头是 "f", 但正则中限制了开始为 i 所以找不到

    regex = re.compile("^i\w+")

    print regex.match(s)

    # output> None

    purge()

    当你在程序中使用 re 模块,无论是先使用 compile 还是直接使用比如 findall 来使用正则表达式操作文本,re 模块都会将正则表达式先编译一下, 并且会将编译过后的正则表达式放到缓存中,这样下次使用同样的正则表达式的时候就不需要再次编译, 因为编译其实是很费时的,这样可以提升效率,而默认缓存的正则表达式的个数是 100, 当你需要频繁使用少量正则表达式的时候,缓存可以提升效率,而使用的正则表达式过多时,缓存带来的优势就不明显了 (参考 《python re.compile对性能的影响》http://blog.trytofix.com/article/detail/13/), 这个函数的作用是清除缓存中的正则表达式,可能在你需要优化占用内存的时候会用到。

    search(pattern, string, flags=0)

    函数类似于 match,不同之处在于不限制正则表达式的开始匹配位置

    s = '''first line

    second line

    third line'''

    # 需要从开始处匹配 所以匹配不到

    print re.match('i\w+', s)

    # output> None

    # 没有限制起始匹配位置

    print re.search('i\w+', s)

    # output> <_sre.sre_match object at>

    print re.search('i\w+', s).group()

    # output> irst

    split(pattern, string, maxsplit=0, flags=0)

    参数 maxsplit 指定切分次数, 函数使用给定正则表达式寻找切分字符串位置,返回包含切分后子串的列表,如果匹配不到,则返回包含原字符串的一个列表

    s = '''first 111 line

    second 222 line

    third 333 line'''

    # 按照数字切分

    print re.split('\d+', s)

    # output> ['first ', ' line\nsecond ', ' line\nthird ', ' line']

    # \.+ 匹配不到 返回包含自身的列表

    print re.split('\.+', s, 1)

    # output> ['first 111 line\nsecond 222 line\nthird 333 line']

    # maxsplit 参数

    print re.split('\d+', s, 1)

    # output> ['first ', ' line\nsecond 222 line\nthird 333 line']

    sub(pattern, repl, string, count=0, flags=0)

    替换函数,将正则表达式 pattern 匹配到的字符串替换为 repl 指定的字符串,  参数 count 用于指定最大替换次数

    s = "the sum of 7 and 9 is [7+9]."

    # 基本用法 将目标替换为固定字符串

    print re.sub('\[7\+9\]', '16', s)

    # output> the sum of 7 and 9 is 16.

    # 高级用法 1 使用前面匹配的到的内容 \1 代表 pattern 中捕获到的第一个分组的内容

    print re.sub('\[(7)\+(9)\]', r'\2\1', s)

    # output> the sum of 7 and 9 is 97.

    # 高级用法 2 使用函数型 repl 参数, 处理匹配到的 SRE_Match 对象

    def replacement(m):

    p_str = m.group()

    if p_str == '7':

    return '77'

    if p_str == '9':

    return '99'

    return ''

    print re.sub('\d', replacement, s)

    # output> the sum of 77 and 99 is [77+99].

    # 高级用法 3 使用函数型 repl 参数, 处理匹配到的 SRE_Match 对象 增加作用域 自动计算

    scope = {}

    example_string_1 = "the sum of 7 and 9 is [7+9]."

    example_string_2 = "[name = 'Mr.Gumby']Hello,[name]"

    def replacement(m):

    code = m.group(1)

    st = ''

    try:

    st = str(eval(code, scope))

    except SyntaxError:

    exec code in scope

    return st

    # 解析: code='7+9'

    # str(eval(code, scope))='16'

    print re.sub('\[(.+?)\]', replacement, example_string_1)

    # output> the sum of 7 and 9 is 16.

    # 两次替换

    # 解析1: code="name = 'Mr.Gumby'"

    # eval(code)

    # raise SyntaxError

    # exec code in scope

    # 在命名空间 scope 中将 "Mr.Gumby" 赋给了变量 name

    # 解析2: code="name"

    # eval(name) 返回变量 name 的值 Mr.Gumby

    print re.sub('\[(.+?)\]', replacement, example_string_2)

    # output> Hello,Mr.Gumby

    subn(pattern, repl, string, count=0, flags=0)

    作用与函数 sub 一样, 唯一不同之处在于返回值为一个元组,第一个值为替换后的字符串,第二个值为发生替换的次数

    template(pattern, flags=0)

    这个吧,咋一看和 compile 差不多,不过不支持 +、?、*、{} 等这样的元字符,只要是需要有重复功能的元字符,就不支持,查了查资料,貌似没人知道这个函数到底是干嘛的...

    四、re 内置对象用法

    SRE_Pattern    这个对象是一个编译后的正则表达式,编译后不仅能够复用和提升效率,同时也能够获得一些其他的关于正则表达式的信息

    属性:

    flags         编译时指定的模式

    groupindex    以正则表达式中有别名的组的别名为键、以该组对应的编号为值的字典,没有别名的组不包含在内。

    groups        正则表达式中分组的数量

    pattern       编译时用的正则表达式

    s = 'Hello, Mr.Gumby : 2016/10/26'

    p = re.compile('''(?: # 构造一个不捕获分组 用于使用 |

    (?P\w+\.\w+) # 匹配 Mr.Gumby

    | # 或

    (?P\s+\.\w+) # 一个匹配不到的命名分组

    )

    .*? # 匹配 :

    (\d+) # 匹配 2016

    ''', re.X)

    #

    print p.flags

    # output> 64

    print p.groupindex

    # output> {'name': 1, 'no': 2}

    print p.groups

    # output> 3

    print p.pattern

    # output> (?: # 构造一个不捕获分组 用于使用 |

    # (?P\w+\.\w+) # 匹配 Mr.Gumby

    # | # 或

    # (?P\s+\.\w+) # 一个匹配不到的命名分组

    # )

    # .*? # 匹配 :

    # (\d+) # 匹配 2016

    函数:可使用 findall、finditer、match、search、split、sub、subn 等函数

    SRE_Match    这个对象会保存本次匹配的结果,包含很多关于匹配过程以及匹配结果的信息

    属性:

    endpos       本次搜索结束位置索引

    lastgroup    本次搜索匹配到的最后一个分组的别名

    lastindex    本次搜索匹配到的最后一个分组的索引

    pos          本次搜索开始位置索引

    re           本次搜索使用的 SRE_Pattern 对象

    regs         列表,元素为元组,包含本次搜索匹配到的所有分组的起止位置

    string       本次搜索操作的字符串

    s = 'Hello, Mr.Gumby : 2016/10/26'

    m = re.search(', (?P\w+\.\w+).*?(\d+)', s)

    # 本次搜索的结束位置索引

    print m.endpos

    # output> 28

    # 本次搜索匹配到的最后一个分组的别名

    # 本次匹配最后一个分组没有别名

    print m.lastgroup

    # output> None

    # 本次搜索匹配到的最后一个分组的索引

    print m.lastindex

    # output> 2

    # 本次搜索开始位置索引

    print m.pos

    # output> 0

    # 本次搜索使用的 SRE_Pattern 对象

    print m.re

    # output> <_sre.sre_pattern object at>

    # 列表,元素为元组,包含本次搜索匹配到的所有分组的起止位置 第一个元组为正则表达式匹配范围

    print m.regs

    # output> ((7, 22), (7, 15), (18, 22))

    # 本次搜索操作的字符串

    print m.string

    # output> Hello, Mr.Gumby : 2016/10/26

    函数:

    end([group=0])               返回指定分组的结束位置,默认返回正则表达式所匹配到的最后一个字符的索引

    expand(template)             根据模版返回相应的字符串,类似与 sub 函数里面的 repl, 可使用 \1 或者 \g 来选择分组

    group([group1, ...])         根据提供的索引或名字返回响应分组的内容,默认返回 start() 到 end() 之间的字符串, 提供多个参数将返回一个元组

    groupdict([default=None])    返回 返回一个包含所有匹配到的命名分组的字典,没有命名的分组不包含在内,key 为组名, value 为匹配到的内容,参数 default 为没有参与本次匹配的命名分组提供默认值

    groups([default=None])       以元组形式返回每一个分组匹配到的字符串,包括没有参与匹配的分组,其值为 default

    span([group])                返回指定分组的起止位置组成的元组,默认返回由 start() 和 end() 组成的元组

    start([group])               返回指定分组的开始位置,默认返回正则表达式所匹配到的第一个字符的索引

    s = 'Hello, Mr.Gumby : 2016/10/26'

    m = re.search('''(?: # 构造一个不捕获分组 用于使用 |

    (?P\w+\.\w+) # 匹配 Mr.Gumby

    | # 或

    (?P\s+\.\w+) # 一个匹配不到的命名分组

    )

    .*? # 匹配 :

    (\d+) # 匹配 2016

    ''',

    s, re.X)

    # 返回指定分组的结束位置,默认返回正则表达式所匹配到的最后一个字符的索引

    print m.end()

    # output> 22

    # 根据模版返回相应的字符串,类似与 sub 函数里面的 repl, 可使用 \1 或者 \g 来选择分组

    print m.expand("my name is \\1")

    # output> my name is Mr.Gumby

    # 根据提供的索引或名字返回响应分组的内容,默认返回 start() 到 end() 之间的字符串, 提供多个参数将返回一个元组

    print m.group()

    # output> Mr.Gumby : 2016

    print m.group(1,2)

    # output> ('Mr.Gumby', None)

    # 返回 返回一个包含所有匹配到的命名分组的字典,没有命名的分组不包含在内,key 为组名, value 为匹配到的内容,参数 default 为没有参与本次匹配的命名分组提供默认值

    print m.groupdict('default_string')

    # output> {'name': 'Mr.Gumby', 'no': 'default_string'}

    # 以元组形式返回每一个分组匹配到的字符串,包括没有参与匹配的分组,其值为 default

    print m.groups('default_string')

    # output> ('Mr.Gumby', 'default_string', '2016')

    # 返回指定分组的起止未知组成的元组,默认返回由 start() 和 end() 组成的元组

    print m.span(3)

    # output> (18, 22)

    # 返回指定分组的开始位置,默认返回正则表达式所匹配到的第一个字符的索引

    print m.start(3)

    # output> 18

    五、分组用法

    python 的正则表达式中用小括号 "(" 表示分组,按照每个分组中前半部分出现的顺序 "(" 判定分组的索引,索引从 1 开始,每个分组在访问的时候可以使用索引,也可以使用别名

    s = 'Hello, Mr.Gumby : 2016/10/26'

    p = re.compile("(?P\w+\.\w+).*?(\d+)(?#comment)")

    m = p.search(s)

    # 使用别名访问

    print m.group('name')

    # output> Mr.Gumby

    # 使用分组访问

    print m.group(2)

    # output> 2016

    有时候可能只是为了把正则表达式分组,而不需要捕获其中的内容,这时候可以使用非捕获分组

    s = 'Hello, Mr.Gumby : 2016/10/26'

    p = re.compile("""

    (?: # 非捕获分组标志 用于使用 |

    (?P\w+\.\w+)

    |

    (\d+/)

    )

    """, re.X)

    m = p.search(s)

    # 使用非捕获分组

    # 此分组将不计入 SRE_Pattern 的 分组计数

    print p.groups

    # output> 2

    # 不计入 SRE_Match 的分组

    print m.groups()

    # output> ('Mr.Gumby', None)

    如果你在写正则的时候需要在正则里面重复书写某个表达式,那么你可以使用正则的引用分组功能,需要注意的是引用的不是前面分组的 正则表达式而是捕获到的 内容,并且引用的分组不算在分组总数中.

    s = 'Hello, Mr.Gumby : 2016/2016/26'

    p = re.compile("""

    (?: # 非捕获分组标志 用于使用 |

    (?P\w+\.\w+)

    |

    (\d+/)

    )

    .*?(?P\d+)/(?P=number)/

    """, re.X)

    m = p.search(s)

    # 使用引用分组

    # 此分组将不计入 SRE_Pattern 的 分组计数

    print p.groups

    # output> 3

    # 不计入 SRE_Match 的分组

    print m.groups()

    # output> ('Mr.Gumby', None, '2016')

    # 查看匹配到的字符串

    print m.group()

    # output> Mr.Gumby : 2016/2016/

    六、环视用法

    环视还有其他的名字,例如 界定、断言、预搜索等,叫法不一。

    环视是一种特殊的正则语法,它匹配的不是字符串,而是 位置,其实就是使用正则来说明这个位置的左右应该是什么或者应该不是什么,然后去寻找这个位置。

    环视的语法有四种,见第一小节元字符,基本用法如下。

    s = 'Hello, Mr.Gumby : 2016/10/26 Hello,r.Gumby : 2016/10/26'

    # 不加环视限定

    print re.compile("(?P\w+\.\w+)").findall(s)

    # output> ['Mr.Gumby', 'r.Gumby']

    # 环视表达式所在位置 左边为 "Hello, "

    print re.compile("(?<=Hello, )(?P\w+\.\w+)").findall(s)

    # output> ['Mr.Gumby']

    # 环视表达式所在位置 左边不为 ","

    print re.compile("(?\w+\.\w+)").findall(s)

    # output> ['Mr.Gumby']

    # 环视表达式所在位置 右边为 "M"

    print re.compile("(?=M)(?P\w+\.\w+)").findall(s)

    # output> ['Mr.Gumby']

    # 环视表达式所在位置 右边不为 r

    print re.compile("(?!r)(?P\w+\.\w+)").findall(s)

    # output> ['Mr.Gumby']

    from :https://www.cnblogs.com/misswangxing/p/10736310.html

    更多相关内容
  • Python正则表达式详解

    2020-12-22 06:08:30
    正则表达式并非Python独有,许多编程语言如Java均有对其的实现。Python中主要由re模块实现正则表达式的使用。 2、工具介绍   正则表达式说到底就是一款工具,一款用于匹配字符串的工具。正则表达式内容繁琐,不...
  • Java 正则表达式详解

    2020-12-07 03:36:47
    许多语言,包括Perl、PHP、Python、JavaScript和JScript,都支持用正则表达式处理文本,一些文本编辑器用正则表达式实现高级“搜索-替换”功能。那么Java又怎样呢?本文写作时,一个包含了用正则表达式进行文本处理...
  • 使用正则表达式,用法如下: ## 总结 ## ^ 匹配字符串的开始。 ## $ 匹配字符串的结尾。 ## \b 匹配一个单词的边界。 ## \d 匹配任意数字。 ## \D 匹配任意非数字字符。 ## x? 匹配一个可选的 x 字符 (换言之,它...
  • 正则表达式有元字符及不同组合来构成,通过巧妙的构造正则表达式可以匹配任意字符串,并完成复杂的字符串处理任务
  • 本文是一系列关于Python正则表达式文章的其中一部分。在这个系列的第一篇文章中,我们将重点讨论如何使用Python中的正则表达式并突出Python中一些独有的特性。 我们将介绍Python中对字符串进行搜索和查找的一些方法...
  • Python 自1.5版本起增加了re 模块,它提供 Perl 风格的正则表达式模式。 re 模块使 Python 语言拥有全部的正则表达式功能。 compile 函数根据一个模式字符串和可选的标志参数生成一个正则表达式对象。该对象拥有一...
  • 快速入门 import re pattern = 'this' text = 'Does this text match the pattern?' match = re.search(pattern, text) s = match.start() e = match.end() print('Found {0}\nin {1}'....#python re_simple_matc
  • python正则表达式详解

    2020-11-28 05:55:37
    正则表达式是一个很强大的字符串处理工具,几乎任何关于字符串的操作都可以使用正则表达式来完成,作为一个爬虫工作者,每天和...下面,我来介绍一下python中的正则表达式是怎么使用的。首先,python中的正则表达...

    正则表达式是一个很强大的字符串处理工具,几乎任何关于字符串的操作都可以使用正则表达式来完成,作为一个爬虫工作者,每天和字符串打交道,正则表达式更是不可或缺的技能,正则表达式的在不同的语言中使用方式可能不一样,不过只要学会了任意一门语言的正则表达式用法,其他语言中大部分也只是换了个函数的名称而已,本质都是一样的。下面,我来介绍一下python中的正则表达式是怎么使用的。

    首先,python中的正则表达式大致分为以下几部分:

    元字符

    模式

    函数

    re 内置对象用法

    分组用法

    环视用法

    所有关于正则表达式的操作都使用 python 标准库中的 re 模块。

    一、元字符 (参见 python 模块 re 文档)

    . 匹配任意字符(不包括换行符)

    ^ 匹配开始位置,多行模式下匹配每一行的开始

    $ 匹配结束位置,多行模式下匹配每一行的结束

    * 匹配前一个元字符0到多次

    + 匹配前一个元字符1到多次

    ? 匹配前一个元字符0到1次

    {m,n} 匹配前一个元字符m到n次

    \\ 转义字符,跟在其后的字符将失去作为特殊元字符的含义,例如\\.只能匹配.,不能再匹配任意字符

    [] 字符集,一个字符的集合,可匹配其中任意一个字符

    | 逻辑表达式 或 ,比如 a|b 代表可匹配 a 或者 b

    (...) 分组,默认为捕获,即被分组的内容可以被单独取出,默认每个分组有个索引,从 1 开始,按照"("的顺序决定索引值

    (?iLmsux) 分组中可以设置模式,iLmsux之中的每个字符代表一个模式,用法参见 模式 I

    (?:...) 分组的不捕获模式,计算索引时会跳过这个分组

    (?P...) 分组的命名模式,取此分组中的内容时可以使用索引也可以使用name

    (?P=name) 分组的引用模式,可在同一个正则表达式用引用前面命名过的正则

    (?#...) 注释,不影响正则表达式其它部分,用法参见 模式 I

    (?=...) 顺序肯定环视,表示所在位置右侧能够匹配括号内正则

    (?!...) 顺序否定环视,表示所在位置右侧不能匹配括号内正则

    (?<=...) 逆序肯定环视,表示所在位置左侧能够匹配括号内正则

    (?

    (?(id/name)yes|no) 若前面指定id或name的分区匹配成功则执行yes处的正则,否则执行no处的正则

    \number 匹配和前面索引为number的分组捕获到的内容一样的字符串

    \A 匹配字符串开始位置,忽略多行模式

    \Z 匹配字符串结束位置,忽略多行模式

    \b 匹配位于单词开始或结束位置的空字符串

    \B 匹配不位于单词开始或结束位置的空字符串

    \d 匹配一个数字, 相当于 [0-9]

    \D 匹配非数字,相当于 [^0-9]

    \s 匹配任意空白字符, 相当于 [ \t\n\r\f\v]

    \S 匹配非空白字符,相当于 [^ \t\n\r\f\v]

    \w 匹配数字、字母、下划线中任意一个字符, 相当于 [a-zA-Z0-9_]

    \W 匹配非数字、字母、下划线中的任意字符,相当于 [^a-zA-Z0-9_]

    二、模式

    I IGNORECASE, 忽略大小写的匹配模式, 样例如下

    copycode.gif

    s = 'hello World!'regex= re.compile("hello world!", re.I)printregex.match(s).group()#output> 'Hello World!'

    #在正则表达式中指定模式以及注释

    regex = re.compile("(?#注释)(?i)hello world!")printregex.match(s).group()#output> 'Hello World!'

    copycode.gif

    L LOCALE, 字符集本地化。这个功能是为了支持多语言版本的字符集使用环境的,比如在转义符\w,在英文环境下,它代表[a-zA-Z0-9_],即所以英文字符和数字。如果在一个法语环境下使用,缺省设置下,不能匹配"é" 或 "ç"。加上这L选项和就可以匹配了。不过这个对于中文环境似乎没有什么用,它仍然不能匹配中文字符。

    M MULTILINE,多行模式, 改变 ^ 和 $ 的行为

    copycode.gif

    s = '''first line

    second line

    third line'''

    #^

    regex_start = re.compile("^\w+")printregex_start.findall(s)#output> ['first']

    regex_start_m= re.compile("^\w+", re.M)printregex_start_m.findall(s)#output> ['first', 'second', 'third']

    #$

    regex_end = re.compile("\w+$")printregex_end.findall(s)#output> ['line']

    regex_end_m= re.compile("\w+$", re.M)printregex_end_m.findall(s)#output> ['line', 'line', 'line']

    copycode.gif

    S  DOTALL,此模式下 '.' 的匹配不受限制,可匹配任何字符,包括换行符

    copycode.gif

    s = '''first line

    second line

    third line'''

    #regex = re.compile(".+")printregex.findall(s)#output> ['first line', 'second line', 'third line']

    #re.S

    regex_dotall = re.compile(".+", re.S)printregex_dotall.findall(s)#output> ['first line\nsecond line\nthird line']

    copycode.gif

    X VERBOSE,冗余模式, 此模式忽略正则表达式中的空白和#号的注释,例如写一个匹配邮箱的正则表达式

    email_regex = re.compile("[\w+\.]+@[a-zA-Z\d]+\.(com|cn)")

    email_regex= re.compile("""[\w+\.]+ # 匹配@符前的部分

    @ # @符

    [a-zA-Z\d]+ # 邮箱类别

    \.(com|cn) # 邮箱后缀""", re.X)

    U UNICODE,使用 \w, \W, \b, \B 这些元字符时将按照 UNICODE 定义的属性.

    正则表达式的模式是可以同时使用多个的,在 python 里面使用按位或运算符 | 同时添加多个模式

    如 re.compile('', re.I|re.M|re.S)

    每个模式在 re 模块中其实就是不同的数字

    copycode.gif

    printre.I#output> 2

    printre.L#output> 4

    printre.M#output> 8

    printre.S#output> 16

    printre.X#output> 64

    printre.U#output> 32

    copycode.gif

    三、函数 (参见 python 模块 re 文档)

    python 的 re 模块提供了很多方便的函数使你可以使用正则表达式来操作字符串,每种函数都有它自己的特性和使用场景,熟悉之后对你的工作会有很大帮助

    compile(pattern, flags=0)

    给定一个正则表达式 pattern,指定使用的模式 flags 默认为0 即不使用任何模式,然后会返回一个 SRE_Pattern (参见 第四小节 re 内置对象用法) 对象

    regex = re.compile(".+")printregex#output> <_sre.SRE_Pattern object at 0x00000000026BB0B8>

    这个对象可以调用其他函数来完成匹配,一般来说推荐使用 compile 函数预编译出一个正则模式之后再去使用,这样在后面的代码中可以很方便的复用它,当然大部分函数也可以不用 compile 直接使用,具体见 findall 函数

    copycode.gif

    s = '''first line

    second line

    third line'''

    #regex = re.compile(".+")

    # 调用 findall 函数printregex.findall(s)#output> ['first line', 'second line', 'third line']

    # 调用 search 函数

    printregex.search(s).group()#output> first lin

    copycode.gif

    escape(pattern)

    转义 如果你需要操作的文本中含有正则的元字符,你在写正则的时候需要将元字符加上反斜扛 \ 去匹配自身, 而当这样的字符很多时,写出来的正则表达式就看起来很乱而且写起来也挺麻烦的,这个时候你可以使用这个函数,用法如下

    copycode.gif

    s = ".+\d123"

    #regex_str = re.escape(".+\d123")#查看转义后的字符

    printregex_str#output> \.\+\\d123

    #查看匹配到的结果

    for g inre.findall(regex_str, s):printg#output> .+\d123

    copycode.gif

    findall(pattern, string, flags=0)

    参数 pattern 为正则表达式, string 为待操作字符串, flags 为所用模式,函数作用为在待操作字符串中寻找所有匹配正则表达式的字串,返回一个列表,如果没有匹配到任何子串,返回一个空列表。

    copycode.gif

    s = '''first line

    second line

    third line'''

    #compile 预编译后使用 findall

    regex = re.compile("\w+")printregex.findall(s)#output> ['first', 'line', 'second', 'line', 'third', 'line']

    #不使用 compile 直接使用 findall

    print re.findall("\w+", s)#output> ['first', 'line', 'second', 'line', 'third', 'line']

    copycode.gif

    finditer(pattern, string, flags=0)

    参数和作用与 findall 一样,不同之处在于 findall 返回一个列表, finditer 返回一个迭代器(参见 http://www.cnblogs.com/huxi/archive/2011/07/01/2095931.html ), 而且迭代器每次返回的值并不是字符串,而是一个 SRE_Match (参见 第四小节 re 内置对象用法) 对象,这个对象的具体用法见 match 函数。

    copycode.gif

    s = '''first line

    second line

    third line'''regex= re.compile("\w+")printregex.finditer(s)#output>

    for i inregex.finditer(s):printi#output> <_sre.SRE_Match object at 0x0000000002B7A920>#<_sre.SRE_Match object at 0x0000000002B7A8B8>#<_sre.SRE_Match object at 0x0000000002B7A920>#<_sre.SRE_Match object at 0x0000000002B7A8B8>#<_sre.SRE_Match object at 0x0000000002B7A920>#<_sre.SRE_Match object at 0x0000000002B7A8B8>

    copycode.gif

    match(pattern, string, flags=0)

    使用指定正则去待操作字符串中寻找可以匹配的子串, 返回匹配上的第一个字串,并且不再继续找,需要注意的是 match 函数是从字符串开始处开始查找的,如果开始处不匹配,则不再继续寻找,返回值为 一个 SRE_Match (参见 第四小节 re 内置对象用法) 对象,找不到时返回 None

    copycode.gif

    s = '''first line

    second line

    third line'''

    #compile

    regex = re.compile("\w+")

    m=regex.match(s)printm#output> <_sre.SRE_Match object at 0x0000000002BCA8B8>

    printm.group()#output> first

    #s 的开头是 "f", 但正则中限制了开始为 i 所以找不到

    regex = re.compile("^i\w+")printregex.match(s)#output> None

    copycode.gif

    purge()

    当你在程序中使用 re 模块,无论是先使用 compile 还是直接使用比如 findall 来使用正则表达式操作文本,re 模块都会将正则表达式先编译一下, 并且会将编译过后的正则表达式放到缓存中,这样下次使用同样的正则表达式的时候就不需要再次编译, 因为编译其实是很费时的,这样可以提升效率,而默认缓存的正则表达式的个数是 100, 当你需要频繁使用少量正则表达式的时候,缓存可以提升效率,而使用的正则表达式过多时,缓存带来的优势就不明显了 (参考 《python re.compile对性能的影响》http://blog.trytofix.com/article/detail/13/), 这个函数的作用是清除缓存中的正则表达式,可能在你需要优化占用内存的时候会用到。

    search(pattern, string, flags=0)

    函数类似于 match,不同之处在于不限制正则表达式的开始匹配位置

    copycode.gif

    s = '''first line

    second line

    third line'''

    #需要从开始处匹配 所以匹配不到

    print re.match('i\w+', s)#output> None

    #没有限制起始匹配位置

    print re.search('i\w+', s)#output> <_sre.SRE_Match object at 0x0000000002C6A920>

    print re.search('i\w+', s).group()#output> irst

    copycode.gif

    split(pattern, string, maxsplit=0, flags=0)

    参数 maxsplit 指定切分次数, 函数使用给定正则表达式寻找切分字符串位置,返回包含切分后子串的列表,如果匹配不到,则返回包含原字符串的一个列表

    copycode.gif

    s = '''first 111 line

    second 222 line

    third 333 line'''

    #按照数字切分

    print re.split('\d+', s)#output> ['first ', ' line\nsecond ', ' line\nthird ', ' line']

    #\.+ 匹配不到 返回包含自身的列表

    print re.split('\.+', s, 1)#output> ['first 111 line\nsecond 222 line\nthird 333 line']

    #maxsplit 参数

    print re.split('\d+', s, 1)#output> ['first ', ' line\nsecond 222 line\nthird 333 line']

    copycode.gif

    sub(pattern, repl, string, count=0, flags=0)

    替换函数,将正则表达式 pattern 匹配到的字符串替换为 repl 指定的字符串, 参数 count 用于指定最大替换次数

    copycode.gif

    s = "the sum of 7 and 9 is [7+9]."

    #基本用法 将目标替换为固定字符串

    print re.sub('\[7\+9\]', '16', s)#output> the sum of 7 and 9 is 16.

    #高级用法 1 使用前面匹配的到的内容 \1 代表 pattern 中捕获到的第一个分组的内容

    print re.sub('\[(7)\+(9)\]', r'\2\1', s)#output> the sum of 7 and 9 is 97.

    #高级用法 2 使用函数型 repl 参数, 处理匹配到的 SRE_Match 对象

    defreplacement(m):

    p_str=m.group()if p_str == '7':return '77'

    if p_str == '9':return '99'

    return ''

    print re.sub('\d', replacement, s)#output> the sum of 77 and 99 is [77+99].

    #高级用法 3 使用函数型 repl 参数, 处理匹配到的 SRE_Match 对象 增加作用域 自动计算

    scope ={}

    example_string_1= "the sum of 7 and 9 is [7+9]."example_string_2= "[name = 'Mr.Gumby']Hello,[name]"

    defreplacement(m):

    code= m.group(1)

    st= ''

    try:

    st=str(eval(code, scope))exceptSyntaxError:exec code inscopereturnst#解析: code='7+9'#str(eval(code, scope))='16'

    print re.sub('\[(.+?)\]', replacement, example_string_1)#output> the sum of 7 and 9 is 16.

    #两次替换#解析1: code="name = 'Mr.Gumby'"#eval(code)#raise SyntaxError#exec code in scope#在命名空间 scope 中将 "Mr.Gumby" 赋给了变量 name

    #解析2: code="name"#eval(name) 返回变量 name 的值 Mr.Gumby

    print re.sub('\[(.+?)\]', replacement, example_string_2)#output> Hello,Mr.Gumby

    copycode.gif

    subn(pattern, repl, string, count=0, flags=0)

    作用与函数 sub 一样, 唯一不同之处在于返回值为一个元组,第一个值为替换后的字符串,第二个值为发生替换的次数

    template(pattern, flags=0)

    这个吧,咋一看和 compile 差不多,不过不支持 +、?、*、{} 等这样的元字符,只要是需要有重复功能的元字符,就不支持,查了查资料,貌似没人知道这个函数到底是干嘛的...

    四、re 内置对象用法

    SRE_Pattern 这个对象是一个编译后的正则表达式,编译后不仅能够复用和提升效率,同时也能够获得一些其他的关于正则表达式的信息

    属性:

    flags 编译时指定的模式

    groupindex 以正则表达式中有别名的组的别名为键、以该组对应的编号为值的字典,没有别名的组不包含在内。

    groups 正则表达式中分组的数量

    pattern 编译时用的正则表达式

    copycode.gif

    s = 'Hello, Mr.Gumby : 2016/10/26'p= re.compile('''(?: # 构造一个不捕获分组 用于使用 |

    (?P\w+\.\w+) # 匹配 Mr.Gumby

    | # 或

    (?P\s+\.\w+) # 一个匹配不到的命名分组

    )

    .*? # 匹配 :

    (\d+) # 匹配 2016''', re.X)#printp.flags#output> 64

    printp.groupindex#output> {'name': 1, 'no': 2}

    printp.groups#output> 3

    printp.pattern#output> (?: # 构造一个不捕获分组 用于使用 |#(?P\w+\.\w+) # 匹配 Mr.Gumby#| # 或#(?P\s+\.\w+) # 一个匹配不到的命名分组#)#.*? # 匹配 :#(\d+) # 匹配 2016

    copycode.gif

    函数:可使用 findall、finditer、match、search、split、sub、subn 等函数

    SRE_Match 这个对象会保存本次匹配的结果,包含很多关于匹配过程以及匹配结果的信息

    属性:

    endpos 本次搜索结束位置索引

    lastgroup 本次搜索匹配到的最后一个分组的别名

    lastindex 本次搜索匹配到的最后一个分组的索引

    pos 本次搜索开始位置索引

    re 本次搜索使用的 SRE_Pattern 对象

    regs 列表,元素为元组,包含本次搜索匹配到的所有分组的起止位置

    string 本次搜索操作的字符串

    copycode.gif

    s = 'Hello, Mr.Gumby : 2016/10/26'm = re.search(', (?P\w+\.\w+).*?(\d+)', s)# 本次搜索的结束位置索引print m.endpos# output> 28# 本次搜索匹配到的最后一个分组的别名# 本次匹配最后一个分组没有别名print m.lastgroup# output> None# 本次搜索匹配到的最后一个分组的索引print m.lastindex# output> 2# 本次搜索开始位置索引print m.pos# output> 0# 本次搜索使用的 SRE_Pattern 对象print m.re# output> <_sre.SRE_Pattern object at 0x000000000277E158># 列表,元素为元组,包含本次搜索匹配到的所有分组的起止位置 第一个元组为正则表达式匹配范围print m.regs# output> ((7, 22), (7, 15), (18, 22))# 本次搜索操作的字符串print m.string# output> Hello, Mr.Gumby : 2016/10/26

    copycode.gif

    函数:

    end([group=0]) 返回指定分组的结束位置,默认返回正则表达式所匹配到的最后一个字符的索引

    expand(template) 根据模版返回相应的字符串,类似与 sub 函数里面的 repl, 可使用 \1 或者 \g 来选择分组

    group([group1, ...]) 根据提供的索引或名字返回响应分组的内容,默认返回 start() 到 end() 之间的字符串, 提供多个参数将返回一个元组

    groupdict([default=None]) 返回 返回一个包含所有匹配到的命名分组的字典,没有命名的分组不包含在内,key 为组名, value 为匹配到的内容,参数 default 为没有参与本次匹配的命名分组提供默认值

    groups([default=None]) 以元组形式返回每一个分组匹配到的字符串,包括没有参与匹配的分组,其值为 default

    span([group]) 返回指定分组的起止位置组成的元组,默认返回由 start() 和 end() 组成的元组

    start([group]) 返回指定分组的开始位置,默认返回正则表达式所匹配到的第一个字符的索引

    copycode.gif

    s = 'Hello, Mr.Gumby : 2016/10/26'm= re.search('''(?: # 构造一个不捕获分组 用于使用 |

    (?P\w+\.\w+) # 匹配 Mr.Gumby

    | # 或

    (?P\s+\.\w+) # 一个匹配不到的命名分组

    )

    .*? # 匹配 :

    (\d+) # 匹配 2016''',

    s, re.X)#返回指定分组的结束位置,默认返回正则表达式所匹配到的最后一个字符的索引

    printm.end()#output> 22

    #根据模版返回相应的字符串,类似与 sub 函数里面的 repl, 可使用 \1 或者 \g 来选择分组

    print m.expand("my name is \\1")#output> my name is Mr.Gumby

    #根据提供的索引或名字返回响应分组的内容,默认返回 start() 到 end() 之间的字符串, 提供多个参数将返回一个元组

    printm.group()#output> Mr.Gumby : 2016

    print m.group(1,2)#output> ('Mr.Gumby', None)

    #返回 返回一个包含所有匹配到的命名分组的字典,没有命名的分组不包含在内,key 为组名, value 为匹配到的内容,参数 default 为没有参与本次匹配的命名分组提供默认值

    print m.groupdict('default_string')#output> {'name': 'Mr.Gumby', 'no': 'default_string'}

    #以元组形式返回每一个分组匹配到的字符串,包括没有参与匹配的分组,其值为 default

    print m.groups('default_string')#output> ('Mr.Gumby', 'default_string', '2016')

    #返回指定分组的起止未知组成的元组,默认返回由 start() 和 end() 组成的元组

    print m.span(3)#output> (18, 22)

    #返回指定分组的开始位置,默认返回正则表达式所匹配到的第一个字符的索引

    print m.start(3)#output> 18

    copycode.gif

    五、分组用法

    python 的正则表达式中用小括号 "(" 表示分组,按照每个分组中前半部分出现的顺序 "(" 判定分组的索引,索引从 1 开始,每个分组在访问的时候可以使用索引,也可以使用别名

    copycode.gif

    s = 'Hello, Mr.Gumby : 2016/10/26'p= re.compile("(?P\w+\.\w+).*?(\d+)(?#comment)")

    m=p.search(s)#使用别名访问

    print m.group('name')#output> Mr.Gumby#使用分组访问

    print m.group(2)#output> 2016

    copycode.gif

    有时候可能只是为了把正则表达式分组,而不需要捕获其中的内容,这时候可以使用非捕获分组

    copycode.gif

    s = 'Hello, Mr.Gumby : 2016/10/26'p= re.compile("""(?: # 非捕获分组标志 用于使用 |

    (?P\w+\.\w+)

    |

    (\d+/)

    )""", re.X)

    m=p.search(s)#使用非捕获分组#此分组将不计入 SRE_Pattern 的 分组计数

    printp.groups#output> 2

    #不计入 SRE_Match 的分组

    printm.groups()#output> ('Mr.Gumby', None)

    copycode.gif

    如果你在写正则的时候需要在正则里面重复书写某个表达式,那么你可以使用正则的引用分组功能,需要注意的是引用的不是前面分组的 正则表达式而是捕获到的 内容,并且引用的分组不算在分组总数中.

    copycode.gif

    s = 'Hello, Mr.Gumby : 2016/2016/26'p= re.compile("""(?: # 非捕获分组标志 用于使用 |

    (?P\w+\.\w+)

    |

    (\d+/)

    )

    .*?(?P\d+)/(?P=number)/""", re.X)

    m=p.search(s)#使用引用分组#此分组将不计入 SRE_Pattern 的 分组计数

    printp.groups#output> 3

    #不计入 SRE_Match 的分组

    printm.groups()#output> ('Mr.Gumby', None, '2016')

    #查看匹配到的字符串

    printm.group()#output> Mr.Gumby : 2016/2016/

    copycode.gif

    六、环视用法

    环视还有其他的名字,例如 界定、断言、预搜索等,叫法不一。

    环视是一种特殊的正则语法,它匹配的不是字符串,而是 位置,其实就是使用正则来说明这个位置的左右应该是什么或者应该不是什么,然后去寻找这个位置。

    环视的语法有四种,见第一小节元字符,基本用法如下。

    copycode.gif

    s= 'Hello, Mr.Gumby : 2016/10/26 Hello,r.Gumby : 2016/10/26'

    #不加环视限定

    print re.compile("(?P\w+\.\w+)").findall(s)#output> ['Mr.Gumby', 'r.Gumby']

    #环视表达式所在位置 左边为 "Hello, "

    print re.compile("(?<=Hello, )(?P\w+\.\w+)").findall(s)#output> ['Mr.Gumby']

    #环视表达式所在位置 左边不为 ","

    print re.compile("(?\w+\.\w+)").findall(s)#output> ['Mr.Gumby']

    #环视表达式所在位置 右边为 "M"

    print re.compile("(?=M)(?P\w+\.\w+)").findall(s)#output> ['Mr.Gumby']

    #环视表达式所在位置 右边不为 r

    print re.compile("(?!r)(?P\w+\.\w+)").findall(s)#output> ['Mr.Gumby']

    copycode.gif

    正则表达式是一个很强大的字符串处理工具,几乎任何关于字符串的操作都可以使用正则表达式来完成,作为一个爬虫工作者,每天和字符串打交道,正则表达式更是不可或缺的技能,正则表达式的在不同的语言中使用方式可能不一样,不过只要学会了任意一门语言的正则表达式用法,其他语言中大部分也只是换了个函数的名称而已,本质都是一样的。下面,我来介绍一下python中的正则表达式是怎么使用的。

    首先,python中的正则表达式大致分为以下几部分:

    元字符

    模式

    函数

    re 内置对象用法

    分组用法

    环视用法

    所有关于正则表达式的操作都使用 python 标准库中的 re 模块。

    一、元字符 (参见 python 模块 re 文档)

    . 匹配任意字符(不包括换行符)

    ^ 匹配开始位置,多行模式下匹配每一行的开始

    $ 匹配结束位置,多行模式下匹配每一行的结束

    * 匹配前一个元字符0到多次

    + 匹配前一个元字符1到多次

    ? 匹配前一个元字符0到1次

    {m,n} 匹配前一个元字符m到n次

    \\ 转义字符,跟在其后的字符将失去作为特殊元字符的含义,例如\\.只能匹配.,不能再匹配任意字符

    [] 字符集,一个字符的集合,可匹配其中任意一个字符

    | 逻辑表达式 或 ,比如 a|b 代表可匹配 a 或者 b

    (...) 分组,默认为捕获,即被分组的内容可以被单独取出,默认每个分组有个索引,从 1 开始,按照"("的顺序决定索引值

    (?iLmsux) 分组中可以设置模式,iLmsux之中的每个字符代表一个模式,用法参见 模式 I

    (?:...) 分组的不捕获模式,计算索引时会跳过这个分组

    (?P...) 分组的命名模式,取此分组中的内容时可以使用索引也可以使用name

    (?P=name) 分组的引用模式,可在同一个正则表达式用引用前面命名过的正则

    (?#...) 注释,不影响正则表达式其它部分,用法参见 模式 I

    (?=...) 顺序肯定环视,表示所在位置右侧能够匹配括号内正则

    (?!...) 顺序否定环视,表示所在位置右侧不能匹配括号内正则

    (?<=...) 逆序肯定环视,表示所在位置左侧能够匹配括号内正则

    (?

    (?(id/name)yes|no) 若前面指定id或name的分区匹配成功则执行yes处的正则,否则执行no处的正则

    \number 匹配和前面索引为number的分组捕获到的内容一样的字符串

    \A 匹配字符串开始位置,忽略多行模式

    \Z 匹配字符串结束位置,忽略多行模式

    \b 匹配位于单词开始或结束位置的空字符串

    \B 匹配不位于单词开始或结束位置的空字符串

    \d 匹配一个数字, 相当于 [0-9]

    \D 匹配非数字,相当于 [^0-9]

    \s 匹配任意空白字符, 相当于 [ \t\n\r\f\v]

    \S 匹配非空白字符,相当于 [^ \t\n\r\f\v]

    \w 匹配数字、字母、下划线中任意一个字符, 相当于 [a-zA-Z0-9_]

    \W 匹配非数字、字母、下划线中的任意字符,相当于 [^a-zA-Z0-9_]

    二、模式

    I IGNORECASE, 忽略大小写的匹配模式, 样例如下

    copycode.gif

    s = 'hello World!'regex= re.compile("hello world!", re.I)printregex.match(s).group()#output> 'Hello World!'

    #在正则表达式中指定模式以及注释

    regex = re.compile("(?#注释)(?i)hello world!")printregex.match(s).group()#output> 'Hello World!'

    copycode.gif

    L LOCALE, 字符集本地化。这个功能是为了支持多语言版本的字符集使用环境的,比如在转义符\w,在英文环境下,它代表[a-zA-Z0-9_],即所以英文字符和数字。如果在一个法语环境下使用,缺省设置下,不能匹配"é" 或 "ç"。加上这L选项和就可以匹配了。不过这个对于中文环境似乎没有什么用,它仍然不能匹配中文字符。

    M MULTILINE,多行模式, 改变 ^ 和 $ 的行为

    copycode.gif

    s = '''first line

    second line

    third line'''

    #^

    regex_start = re.compile("^\w+")printregex_start.findall(s)#output> ['first']

    regex_start_m= re.compile("^\w+", re.M)printregex_start_m.findall(s)#output> ['first', 'second', 'third']

    #$

    regex_end = re.compile("\w+$")printregex_end.findall(s)#output> ['line']

    regex_end_m= re.compile("\w+$", re.M)printregex_end_m.findall(s)#output> ['line', 'line', 'line']

    copycode.gif

    S  DOTALL,此模式下 '.' 的匹配不受限制,可匹配任何字符,包括换行符

    copycode.gif

    s = '''first line

    second line

    third line'''

    #regex = re.compile(".+")printregex.findall(s)#output> ['first line', 'second line', 'third line']

    #re.S

    regex_dotall = re.compile(".+", re.S)printregex_dotall.findall(s)#output> ['first line\nsecond line\nthird line']

    copycode.gif

    X VERBOSE,冗余模式, 此模式忽略正则表达式中的空白和#号的注释,例如写一个匹配邮箱的正则表达式

    email_regex = re.compile("[\w+\.]+@[a-zA-Z\d]+\.(com|cn)")

    email_regex= re.compile("""[\w+\.]+ # 匹配@符前的部分

    @ # @符

    [a-zA-Z\d]+ # 邮箱类别

    \.(com|cn) # 邮箱后缀""", re.X)

    U UNICODE,使用 \w, \W, \b, \B 这些元字符时将按照 UNICODE 定义的属性.

    正则表达式的模式是可以同时使用多个的,在 python 里面使用按位或运算符 | 同时添加多个模式

    如 re.compile('', re.I|re.M|re.S)

    每个模式在 re 模块中其实就是不同的数字

    copycode.gif

    printre.I#output> 2

    printre.L#output> 4

    printre.M#output> 8

    printre.S#output> 16

    printre.X#output> 64

    printre.U#output> 32

    copycode.gif

    三、函数 (参见 python 模块 re 文档)

    python 的 re 模块提供了很多方便的函数使你可以使用正则表达式来操作字符串,每种函数都有它自己的特性和使用场景,熟悉之后对你的工作会有很大帮助

    compile(pattern, flags=0)

    给定一个正则表达式 pattern,指定使用的模式 flags 默认为0 即不使用任何模式,然后会返回一个 SRE_Pattern (参见 第四小节 re 内置对象用法) 对象

    regex = re.compile(".+")printregex#output> <_sre.SRE_Pattern object at 0x00000000026BB0B8>

    这个对象可以调用其他函数来完成匹配,一般来说推荐使用 compile 函数预编译出一个正则模式之后再去使用,这样在后面的代码中可以很方便的复用它,当然大部分函数也可以不用 compile 直接使用,具体见 findall 函数

    copycode.gif

    s = '''first line

    second line

    third line'''

    #regex = re.compile(".+")

    # 调用 findall 函数printregex.findall(s)#output> ['first line', 'second line', 'third line']

    # 调用 search 函数

    printregex.search(s).group()#output> first lin

    copycode.gif

    escape(pattern)

    转义 如果你需要操作的文本中含有正则的元字符,你在写正则的时候需要将元字符加上反斜扛 \ 去匹配自身, 而当这样的字符很多时,写出来的正则表达式就看起来很乱而且写起来也挺麻烦的,这个时候你可以使用这个函数,用法如下

    copycode.gif

    s = ".+\d123"

    #regex_str = re.escape(".+\d123")#查看转义后的字符

    printregex_str#output> \.\+\\d123

    #查看匹配到的结果

    for g inre.findall(regex_str, s):printg#output> .+\d123

    copycode.gif

    findall(pattern, string, flags=0)

    参数 pattern 为正则表达式, string 为待操作字符串, flags 为所用模式,函数作用为在待操作字符串中寻找所有匹配正则表达式的字串,返回一个列表,如果没有匹配到任何子串,返回一个空列表。

    copycode.gif

    s = '''first line

    second line

    third line'''

    #compile 预编译后使用 findall

    regex = re.compile("\w+")printregex.findall(s)#output> ['first', 'line', 'second', 'line', 'third', 'line']

    #不使用 compile 直接使用 findall

    print re.findall("\w+", s)#output> ['first', 'line', 'second', 'line', 'third', 'line']

    copycode.gif

    finditer(pattern, string, flags=0)

    参数和作用与 findall 一样,不同之处在于 findall 返回一个列表, finditer 返回一个迭代器(参见 http://www.cnblogs.com/huxi/archive/2011/07/01/2095931.html ), 而且迭代器每次返回的值并不是字符串,而是一个 SRE_Match (参见 第四小节 re 内置对象用法) 对象,这个对象的具体用法见 match 函数。

    copycode.gif

    s = '''first line

    second line

    third line'''regex= re.compile("\w+")printregex.finditer(s)#output>

    for i inregex.finditer(s):printi#output> <_sre.SRE_Match object at 0x0000000002B7A920>#<_sre.SRE_Match object at 0x0000000002B7A8B8>#<_sre.SRE_Match object at 0x0000000002B7A920>#<_sre.SRE_Match object at 0x0000000002B7A8B8>#<_sre.SRE_Match object at 0x0000000002B7A920>#<_sre.SRE_Match object at 0x0000000002B7A8B8>

    copycode.gif

    match(pattern, string, flags=0)

    使用指定正则去待操作字符串中寻找可以匹配的子串, 返回匹配上的第一个字串,并且不再继续找,需要注意的是 match 函数是从字符串开始处开始查找的,如果开始处不匹配,则不再继续寻找,返回值为 一个 SRE_Match (参见 第四小节 re 内置对象用法) 对象,找不到时返回 None

    copycode.gif

    s = '''first line

    second line

    third line'''

    #compile

    regex = re.compile("\w+")

    m=regex.match(s)printm#output> <_sre.SRE_Match object at 0x0000000002BCA8B8>

    printm.group()#output> first

    #s 的开头是 "f", 但正则中限制了开始为 i 所以找不到

    regex = re.compile("^i\w+")printregex.match(s)#output> None

    copycode.gif

    purge()

    当你在程序中使用 re 模块,无论是先使用 compile 还是直接使用比如 findall 来使用正则表达式操作文本,re 模块都会将正则表达式先编译一下, 并且会将编译过后的正则表达式放到缓存中,这样下次使用同样的正则表达式的时候就不需要再次编译, 因为编译其实是很费时的,这样可以提升效率,而默认缓存的正则表达式的个数是 100, 当你需要频繁使用少量正则表达式的时候,缓存可以提升效率,而使用的正则表达式过多时,缓存带来的优势就不明显了 (参考 《python re.compile对性能的影响》http://blog.trytofix.com/article/detail/13/), 这个函数的作用是清除缓存中的正则表达式,可能在你需要优化占用内存的时候会用到。

    search(pattern, string, flags=0)

    函数类似于 match,不同之处在于不限制正则表达式的开始匹配位置

    copycode.gif

    s = '''first line

    second line

    third line'''

    #需要从开始处匹配 所以匹配不到

    print re.match('i\w+', s)#output> None

    #没有限制起始匹配位置

    print re.search('i\w+', s)#output> <_sre.SRE_Match object at 0x0000000002C6A920>

    print re.search('i\w+', s).group()#output> irst

    copycode.gif

    split(pattern, string, maxsplit=0, flags=0)

    参数 maxsplit 指定切分次数, 函数使用给定正则表达式寻找切分字符串位置,返回包含切分后子串的列表,如果匹配不到,则返回包含原字符串的一个列表

    copycode.gif

    s = '''first 111 line

    second 222 line

    third 333 line'''

    #按照数字切分

    print re.split('\d+', s)#output> ['first ', ' line\nsecond ', ' line\nthird ', ' line']

    #\.+ 匹配不到 返回包含自身的列表

    print re.split('\.+', s, 1)#output> ['first 111 line\nsecond 222 line\nthird 333 line']

    #maxsplit 参数

    print re.split('\d+', s, 1)#output> ['first ', ' line\nsecond 222 line\nthird 333 line']

    copycode.gif

    sub(pattern, repl, string, count=0, flags=0)

    替换函数,将正则表达式 pattern 匹配到的字符串替换为 repl 指定的字符串, 参数 count 用于指定最大替换次数

    copycode.gif

    s = "the sum of 7 and 9 is [7+9]."

    #基本用法 将目标替换为固定字符串

    print re.sub('\[7\+9\]', '16', s)#output> the sum of 7 and 9 is 16.

    #高级用法 1 使用前面匹配的到的内容 \1 代表 pattern 中捕获到的第一个分组的内容

    print re.sub('\[(7)\+(9)\]', r'\2\1', s)#output> the sum of 7 and 9 is 97.

    #高级用法 2 使用函数型 repl 参数, 处理匹配到的 SRE_Match 对象

    defreplacement(m):

    p_str=m.group()if p_str == '7':return '77'

    if p_str == '9':return '99'

    return ''

    print re.sub('\d', replacement, s)#output> the sum of 77 and 99 is [77+99].

    #高级用法 3 使用函数型 repl 参数, 处理匹配到的 SRE_Match 对象 增加作用域 自动计算

    scope ={}

    example_string_1= "the sum of 7 and 9 is [7+9]."example_string_2= "[name = 'Mr.Gumby']Hello,[name]"

    defreplacement(m):

    code= m.group(1)

    st= ''

    try:

    st=str(eval(code, scope))exceptSyntaxError:exec code inscopereturnst#解析: code='7+9'#str(eval(code, scope))='16'

    print re.sub('\[(.+?)\]', replacement, example_string_1)#output> the sum of 7 and 9 is 16.

    #两次替换#解析1: code="name = 'Mr.Gumby'"#eval(code)#raise SyntaxError#exec code in scope#在命名空间 scope 中将 "Mr.Gumby" 赋给了变量 name

    #解析2: code="name"#eval(name) 返回变量 name 的值 Mr.Gumby

    print re.sub('\[(.+?)\]', replacement, example_string_2)#output> Hello,Mr.Gumby

    copycode.gif

    subn(pattern, repl, string, count=0, flags=0)

    作用与函数 sub 一样, 唯一不同之处在于返回值为一个元组,第一个值为替换后的字符串,第二个值为发生替换的次数

    template(pattern, flags=0)

    这个吧,咋一看和 compile 差不多,不过不支持 +、?、*、{} 等这样的元字符,只要是需要有重复功能的元字符,就不支持,查了查资料,貌似没人知道这个函数到底是干嘛的...

    四、re 内置对象用法

    SRE_Pattern 这个对象是一个编译后的正则表达式,编译后不仅能够复用和提升效率,同时也能够获得一些其他的关于正则表达式的信息

    属性:

    flags 编译时指定的模式

    groupindex 以正则表达式中有别名的组的别名为键、以该组对应的编号为值的字典,没有别名的组不包含在内。

    groups 正则表达式中分组的数量

    pattern 编译时用的正则表达式

    copycode.gif

    s = 'Hello, Mr.Gumby : 2016/10/26'p= re.compile('''(?: # 构造一个不捕获分组 用于使用 |

    (?P\w+\.\w+) # 匹配 Mr.Gumby

    | # 或

    (?P\s+\.\w+) # 一个匹配不到的命名分组

    )

    .*? # 匹配 :

    (\d+) # 匹配 2016''', re.X)#printp.flags#output> 64

    printp.groupindex#output> {'name': 1, 'no': 2}

    printp.groups#output> 3

    printp.pattern#output> (?: # 构造一个不捕获分组 用于使用 |#(?P\w+\.\w+) # 匹配 Mr.Gumby#| # 或#(?P\s+\.\w+) # 一个匹配不到的命名分组#)#.*? # 匹配 :#(\d+) # 匹配 2016

    copycode.gif

    函数:可使用 findall、finditer、match、search、split、sub、subn 等函数

    SRE_Match 这个对象会保存本次匹配的结果,包含很多关于匹配过程以及匹配结果的信息

    属性:

    endpos 本次搜索结束位置索引

    lastgroup 本次搜索匹配到的最后一个分组的别名

    lastindex 本次搜索匹配到的最后一个分组的索引

    pos 本次搜索开始位置索引

    re 本次搜索使用的 SRE_Pattern 对象

    regs 列表,元素为元组,包含本次搜索匹配到的所有分组的起止位置

    string 本次搜索操作的字符串

    copycode.gif

    s = 'Hello, Mr.Gumby : 2016/10/26'm = re.search(', (?P\w+\.\w+).*?(\d+)', s)# 本次搜索的结束位置索引print m.endpos# output> 28# 本次搜索匹配到的最后一个分组的别名# 本次匹配最后一个分组没有别名print m.lastgroup# output> None# 本次搜索匹配到的最后一个分组的索引print m.lastindex# output> 2# 本次搜索开始位置索引print m.pos# output> 0# 本次搜索使用的 SRE_Pattern 对象print m.re# output> <_sre.SRE_Pattern object at 0x000000000277E158># 列表,元素为元组,包含本次搜索匹配到的所有分组的起止位置 第一个元组为正则表达式匹配范围print m.regs# output> ((7, 22), (7, 15), (18, 22))# 本次搜索操作的字符串print m.string# output> Hello, Mr.Gumby : 2016/10/26

    copycode.gif

    函数:

    end([group=0]) 返回指定分组的结束位置,默认返回正则表达式所匹配到的最后一个字符的索引

    expand(template) 根据模版返回相应的字符串,类似与 sub 函数里面的 repl, 可使用 \1 或者 \g 来选择分组

    group([group1, ...]) 根据提供的索引或名字返回响应分组的内容,默认返回 start() 到 end() 之间的字符串, 提供多个参数将返回一个元组

    groupdict([default=None]) 返回 返回一个包含所有匹配到的命名分组的字典,没有命名的分组不包含在内,key 为组名, value 为匹配到的内容,参数 default 为没有参与本次匹配的命名分组提供默认值

    groups([default=None]) 以元组形式返回每一个分组匹配到的字符串,包括没有参与匹配的分组,其值为 default

    span([group]) 返回指定分组的起止位置组成的元组,默认返回由 start() 和 end() 组成的元组

    start([group]) 返回指定分组的开始位置,默认返回正则表达式所匹配到的第一个字符的索引

    copycode.gif

    s = 'Hello, Mr.Gumby : 2016/10/26'm= re.search('''(?: # 构造一个不捕获分组 用于使用 |

    (?P\w+\.\w+) # 匹配 Mr.Gumby

    | # 或

    (?P\s+\.\w+) # 一个匹配不到的命名分组

    )

    .*? # 匹配 :

    (\d+) # 匹配 2016''',

    s, re.X)#返回指定分组的结束位置,默认返回正则表达式所匹配到的最后一个字符的索引

    printm.end()#output> 22

    #根据模版返回相应的字符串,类似与 sub 函数里面的 repl, 可使用 \1 或者 \g 来选择分组

    print m.expand("my name is \\1")#output> my name is Mr.Gumby

    #根据提供的索引或名字返回响应分组的内容,默认返回 start() 到 end() 之间的字符串, 提供多个参数将返回一个元组

    printm.group()#output> Mr.Gumby : 2016

    print m.group(1,2)#output> ('Mr.Gumby', None)

    #返回 返回一个包含所有匹配到的命名分组的字典,没有命名的分组不包含在内,key 为组名, value 为匹配到的内容,参数 default 为没有参与本次匹配的命名分组提供默认值

    print m.groupdict('default_string')#output> {'name': 'Mr.Gumby', 'no': 'default_string'}

    #以元组形式返回每一个分组匹配到的字符串,包括没有参与匹配的分组,其值为 default

    print m.groups('default_string')#output> ('Mr.Gumby', 'default_string', '2016')

    #返回指定分组的起止未知组成的元组,默认返回由 start() 和 end() 组成的元组

    print m.span(3)#output> (18, 22)

    #返回指定分组的开始位置,默认返回正则表达式所匹配到的第一个字符的索引

    print m.start(3)#output> 18

    copycode.gif

    五、分组用法

    python 的正则表达式中用小括号 "(" 表示分组,按照每个分组中前半部分出现的顺序 "(" 判定分组的索引,索引从 1 开始,每个分组在访问的时候可以使用索引,也可以使用别名

    copycode.gif

    s = 'Hello, Mr.Gumby : 2016/10/26'p= re.compile("(?P\w+\.\w+).*?(\d+)(?#comment)")

    m=p.search(s)#使用别名访问

    print m.group('name')#output> Mr.Gumby#使用分组访问

    print m.group(2)#output> 2016

    copycode.gif

    有时候可能只是为了把正则表达式分组,而不需要捕获其中的内容,这时候可以使用非捕获分组

    copycode.gif

    s = 'Hello, Mr.Gumby : 2016/10/26'p= re.compile("""(?: # 非捕获分组标志 用于使用 |

    (?P\w+\.\w+)

    |

    (\d+/)

    )""", re.X)

    m=p.search(s)#使用非捕获分组#此分组将不计入 SRE_Pattern 的 分组计数

    printp.groups#output> 2

    #不计入 SRE_Match 的分组

    printm.groups()#output> ('Mr.Gumby', None)

    copycode.gif

    如果你在写正则的时候需要在正则里面重复书写某个表达式,那么你可以使用正则的引用分组功能,需要注意的是引用的不是前面分组的 正则表达式而是捕获到的 内容,并且引用的分组不算在分组总数中.

    copycode.gif

    s = 'Hello, Mr.Gumby : 2016/2016/26'p= re.compile("""(?: # 非捕获分组标志 用于使用 |

    (?P\w+\.\w+)

    |

    (\d+/)

    )

    .*?(?P\d+)/(?P=number)/""", re.X)

    m=p.search(s)#使用引用分组#此分组将不计入 SRE_Pattern 的 分组计数

    printp.groups#output> 3

    #不计入 SRE_Match 的分组

    printm.groups()#output> ('Mr.Gumby', None, '2016')

    #查看匹配到的字符串

    printm.group()#output> Mr.Gumby : 2016/2016/

    copycode.gif

    六、环视用法

    环视还有其他的名字,例如 界定、断言、预搜索等,叫法不一。

    环视是一种特殊的正则语法,它匹配的不是字符串,而是 位置,其实就是使用正则来说明这个位置的左右应该是什么或者应该不是什么,然后去寻找这个位置。

    环视的语法有四种,见第一小节元字符,基本用法如下。

    copycode.gif

    s= 'Hello, Mr.Gumby : 2016/10/26 Hello,r.Gumby : 2016/10/26'

    #不加环视限定

    print re.compile("(?P\w+\.\w+)").findall(s)#output> ['Mr.Gumby', 'r.Gumby']

    #环视表达式所在位置 左边为 "Hello, "

    print re.compile("(?<=Hello, )(?P\w+\.\w+)").findall(s)#output> ['Mr.Gumby']

    #环视表达式所在位置 左边不为 ","

    print re.compile("(?\w+\.\w+)").findall(s)#output> ['Mr.Gumby']

    #环视表达式所在位置 右边为 "M"

    print re.compile("(?=M)(?P\w+\.\w+)").findall(s)#output> ['Mr.Gumby']

    #环视表达式所在位置 右边不为 r

    print re.compile("(?!r)(?P\w+\.\w+)").findall(s)#output> ['Mr.Gumby']

    copycode.gif

    展开全文
  • python正则表达式详解笔记
  • 正则大同小异,python 中的正则跟其他语言相比略有差异: 1、替换字符串时,替换的字符串可以是一个函数 2、split 函数可以指定分割次数,这会导致有个坑 3、前项界定的表达式必须定长 下面详细描述下 re 模块的使用...
  • 在写正则表达式的时候总会遇到不少的问题, 特别是在表达式有多个元组的时候。下面看下re模块下的findall()函数和多个表达式元组相遇的时候会出现什么样的坑。 代码如下: import re str="a b c d" regex0=re....
  • Python 正则表达式详解(建议收藏!)

    万次阅读 多人点赞 2021-10-01 09:48:35
    目录 匹配字符串 单字符匹配 .... \d 匹配单个数字 ...\s 匹配特殊字符,如空白,空格,tab等 ...正则表达式具有通用型,不仅python里面可以用,其他的语言也一样适用。 python中re模块提供了正则表达...

    目录

    match

    匹配字符串

    单字符匹配

    . 匹配任意一个字符

    \d 匹配数字

    \D 匹配非数字

    \s 匹配特殊字符,如空白,空格,tab等

    \S 匹配非空白

    \w 匹配单词、字符,如大小写字母,数字,_ 下划线

    \W 匹配非单词字符

    [ ] 匹配[ ]中列举的字符

    表示数量

     * 出现0次或无数次

    + 至少出现一次

    ? 1次或则0次

    {m}指定出现m次

    {m,} 至少出现m次

    {m,n} 指定从m-n次的范围

    匹配边界

    $ 匹配结尾字符

    ^ 匹配开头字符

    \b 匹配一个单词的边界

    \B 匹配非单词边界

    匹配分组

    | 匹配左右任意一个表达式

    (ab) 将括号中字符作为一个分组

    search

    findall

    re.s

    sub

    split

    贪婪与非贪婪

    案例

    匹配手机号

    提取网页源码中所有的文字

     提取图片地址


    正则表达式是对字符串提取的一套规则,我们把这个规则用正则里面的特定语法表达出来,去匹配满足这个规则的字符串。正则表达式具有通用型,不仅python里面可以用,其他的语言也一样适用。

    python中re模块提供了正则表达式的功能,常用的有四个方法(match、search、findall)都可以用于匹配字符串

    match

    匹配字符串

    re.match()必须从字符串开头匹配!match方法尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none。主要参数如下:

    re.match(pattern, string)
    # pattern     匹配的正则表达式
    # string      要匹配的字符串

    例子

    import re
    a = re.match('test','testasdtest')  
    print(a)                             #返回一个匹配对象
    print(a.group())                     #返回test,获取不到则报错
    print(a.span())           #返回匹配结果的位置,左闭右开区间
    print(re.match('test','atestasdtest'))  #返回None

    从例子中我们可以看出,re.match()方法返回一个匹配的对象,而不是匹配的内容。如果需要返回内容则需要调用group()。通过调用span()可以获得匹配结果的位置。而如果从起始位置开始没有匹配成功,即便其他部分包含需要匹配的内容,re.match()也会返回None。

    单字符匹配

    以下字符,都匹配单个字符数据。且开头(从字符串0位置开始)没匹配到,即使字符串其他部分包含需要匹配的内容,.match也会返回none

    . 匹配任意一个字符

     使用几个点号就代表几个字符

    import re
    a = re.match('..','testasdtest')  
    print(a.group())   #输出te                             
    b = re.match('ab.','testasdtest')  
    print(b) #返回none,因为表达式是以固定的ab开头然后跟上通配符. 所以必须要先匹配上ab才会往后进行匹配

    \d 匹配数字

     一个\d代表一个数字。开头没匹配到,即使字符串其他部分包含需要匹配的内容,.match也会返回none

    import re
    a = re.match('\d\d','23es12testasdtest')  
    print(a)                               
    b = re.match('\d\d\d','23es12testasdtest')   
    print(b)   #要求匹配三个数字,匹配不到返回none
    c = re.match('\d','es12testasdtest')   
    print(c)   #起始位置没有匹配成功,一样返回none

    \D 匹配非数字

    开头没匹配到,即使字符串其他部分包含需要匹配的内容,.match也会返回none

    import re
    a = re.match('\D','23es12testasdtest')  
    print(a)     #开头为数字所以返回none                          
    b = re.match('\D\D','*es12testasdtest')   
    print(b)   #返回*e

    \s 匹配特殊字符,如空白,空格,tab等

    import re
    print(re.match('\s',' 23es 12testasdtest'))   #匹配空格
    print(re.match('\s','   23es 12testasdtest')) #匹配tab
    print(re.match('\s','\r23es 12testasdtest')) #匹配\r换行
    print(re.match('\s','23es 12testasdtest')) #返回none

    \S 匹配非空白

    import re
    print(re.match('\S',' 23es 12testasdtest'))   #返回none
    print(re.match('\S','\r23es 12testasdtest'))   #none
    print(re.match('\S','23es 12testasdtest'))   

    \w 匹配单词、字符,如大小写字母,数字,_ 下划线

    import re
    print(re.match('\w','23es 12testasdtest'))   #返回none
    print(re.match('\w\w\w','aA_3es 12testasdtest'))   #返回none
    print(re.match('\w\w\w','\n12testasdtest'))   #返回none
    

    \W 匹配非单词字符

    import re
    print(re.match('\W','23es 12testasdtest'))   #返回none
    print(re.match('\W',' 23es 12testasdtest'))   #匹配空格

    [ ] 匹配[ ]中列举的字符

    只允许出现[ ]中列举的字符

    import re
    print(re.match('12[234]','232s12testasdtest'))  #因为开头的12没匹配上,所以直接返回none
    print(re.match('12[234]','1232s12testasdtest')) #返回123

    [^2345] 不匹配2345中的任意一个

    import re
    print(re.match('12[^234]','232s12testasdtest'))  #因为开头的12没匹配上,所以直接返回none
    print(re.match('12[^234]','1232s12testasdtest')) #返回none
    print(re.match('12[^234]','1252s12testasdtest')) #返回125

    [a-z3-5] 匹配a-z或者3-5中的字符

    import re
    print(re.match('12[1-3a-c]','1232b12testasdtest'))  #123
    print(re.match('12[1-3a-c]','12b2b12testasdtest'))  #12b
    print(re.match('12[1-3a-c]','12s2b12testasdtest'))  #返回none

    表示数量

     像上面写的那些都是匹配单个字符,如果我们要匹配多个字符的话,只能重复写匹配符。这样显然是不人性化的,所以我们还需要学习表达数量的字符

     * 出现0次或无数次

    import re
    a = re.match('..','testasdtest')  
    print(a.group())   #输出te                             
    a = re.match('.*','testasdtest')  
    print(a.group())   #全部输出

    import re
    print(re.match('a*','aatestasdtest')) #匹配跟随在字母a后面的所有a字符
    print(re.match('\d*','23aatestasdtest')) #匹配前面为数字的字符
    print(re.match('a\d*','ad23aatestasdtest')) #输出a, 因为*也可以代表0次
    

    + 至少出现一次

    import re
    print(re.match('a+','aaatestasdtest')) #匹配前面为字母a的字符,且a至少有1一个
    print(re.match('a+','atestasdtest'))   #a
    print(re.match('a+','caaatestasdtest'))  #none

    ? 1次或则0次

    import re
    print(re.match('a?','abatestasdtest')) #匹配a出现0次或者1次数
    print(re.match('a?','batestasdtest'))  #输出空,因为a可以为0次
    print(re.match('a?','aaatestasdtest')) #a出现0次或者1次,输出1个a

    {m}指定出现m次

    import re
    print(re.match('to{3}','toooooabatestasdtest')) #匹配t以及跟随在后面的三个ooo
    print(re.match('to{3}','tooabatestasdtest')) #只有两个0,返回none

    {m,} 至少出现m次

    import re
    print(re.match('to{3,}','toooooabatestasdtest')) #匹配t以及跟随在后面的三个ooo至少出现3次
    print(re.match('to{3,}','tooabatestasdtest')) #只有两个0,返回none

    {m,n} 指定从m-n次的范围

    import re
    print(re.match('to{3,4}','toooabatestasdtest')) #刚好有三个ooo,成功匹配
    print(re.match('to{3,4}','tooabatestasdtest'))  #只有两个o,返回none
    print(re.match('to{3,4}','toooooabatestasdtest')) #提取最多四个o

    匹配边界

    $ 匹配结尾字符

    定义整个字符串必须以指定字符串结尾

    import re
    print(re.match('.*d$','2testaabcd')) #字符串必须以d结尾 
    print(re.match('.*c','2testaabcd'))  #字符串不是以c结尾,返回none

     

    ^ 匹配开头字符

    定义整个字符串必须以指定字符开头

    import re
    print(re.match('^2','2stoooabatestas')) #规定必须以2开头,否则none 
    print(re.match('^2s','2stoooabatestas')) #必须以2s开头

    \b 匹配一个单词的边界

    \b:表示字母数字与非字母数字的边界,非字母数字与字母数字的边界。即下面ve的右边不能有字母和数字

    import re
    print(re.match(r'.*ve\b','ve.2testaabcd'))  #因为在python中\代表转义,所以前面加上r消除转义
    print(re.match(r'.*ve\b','ve2testaabcd'))

    \B 匹配非单词边界

    import re
    print(re.match(r'.*ve\B','2testaavebcdve'))  #ve的右边需要有字母或者数字 
    print(re.match(r'.*ve\B','2testaave3bcdve'))

    匹配分组

     

    | 匹配左右任意一个表达式

    只要|两边任意一个表达式符合要求就行

    import re
    print(re.match(r'\d[1-9]|\D[a-z]','2233'))  #匹配|两边任意一个表达式
    print(re.match(r'\d[1-9]|\D[a-z]','as'))  

    (ab) 将括号中字符作为一个分组

    ()中的内容会作为一个元组字符装在元组中

    import re
    a = re.match(r'<h1>(.*)<h1>','<h1>你好啊<h1>')
    print(a.group())    #输出匹配的字符
    print(a.groups())   #会将()中的内容会作为一个元组字符装在元组中
    print('`````````````')
    b = re.match(r'<h1>(.*)(<h1>)','<h1>你好啊<h1>')
    print(b.groups()) #有两括号就分为两个元组元素
    print(b.group(0))  #group中默认是0
    print(b.group(1))  #你好啊
    print(b.group(2))  #h1

    search

    和match差不多用法,从字符串中进行搜索

    import re
    print(re.match(r'\d\d','123test123test'))
    print(re.search(r'\d\d','123test123test'))

    findall

    从字面意思上就可以看到,findall是寻找所有能匹配到的字符,并以列表的方式返回

    import re
    print(re.search(r'test','123test123test'))
    print(re.findall(r'test','123test123test'))  #以列表的方式返回

    re.s

    findall中另外一个属性re.S

    在字符串a中,包含换行符\n,在这种情况下

    • 如果不使用re.S参数,则只在每一行内进行匹配,如果一行没有,就换下一行重新开始。
    • 而使用re.S参数以后,正则表达式会将这个字符串作为一个整体,在整体中进行匹配。

     如下要寻找test.*123的数据,因为test和123在不同的行,如果没加re.s的话,他会在每一个进行匹配查找而不是将字符串作为一个整体进行查找

    import re
    a = """aaatestaa     
    aaaa123"""
    print(re.findall(r'test.*123',a))       
    print(re.findall(r'test.*123',a,re.S))

    sub

    查找字符串中所有相匹配的数据进行替换

    sub(要替换的数据,替换成什么,要替换的数据所在的数据)

    import re
    print(re.sub('php','python','php是世界上最好的语言——php'))  
    #输出 "python是世界上最好的语言——python"
    

    split

    对字符串进行分割,并返回一个列表

    import re
    s = "itcase,java:php-php3;html"
    print(re.split(r",",s))           #以,号进行分割
    print(re.split(r",|:|-|;",s))     #以,或者:或者-或者;进行分割
    print(re.split(r",|:|-|%",s))    #找不到的分隔符就忽略

    贪婪与非贪婪

    python里的数量词默认是贪婪的,总是尝试尽可能的匹配更多的字符。python中使用?号关闭贪婪模式

    import re
    print(re.match(r"aa\d+","aa2323"))   #会尽可能多的去匹配\d
    print(re.match(r"aa\d+?","aa2323"))  #尽可能少的去匹配\d

    import re
    s = "this is a number 234-235-22-423"
    # 1.贪婪模式
    resule = re.match(r"(.+)(\d+-\d+-\d+-\d)",s)   #我们本想数字和字母拆解成两个分组
    print(resule.groups())  #('this is a number 23', '4-235-22-4')但我们发现输出的结果中23的数字竟然被弄到前面去了
    
    #因为+它会尽可能多的进行匹配,\d,只需要一个4就能满足,所以前面就尽可能多的匹配
    # 2.关闭贪婪模式
    #在数量词后面加上 ?,进入非贪婪模式,尽可能少的进行匹配
    result = re.match(r"(.+?)(\d+-\d+-\d+-\d)",s)
    print(result.groups())   #('this is a number ', '234-235-22-4')

    案例

    匹配手机号

    要求,手机号为11位,必须以1开头,且第二个数字为35678其种一个

    import re
    result = re.match(r'1[35678]\d{9}','13111111111')
    print(result.group())   #匹配成功
    result = re.match(r'1[35678]\d{9}','12111111111')
    print(result)     #none,第二位为2
    result = re.match(r'1[35678]\d{9}','121111111112')
    print(result)     #none,有12位

    提取网页源码中所有的文字

    如下,将其中的所有文字提取出来,去掉标签。思路就是运用sub方法,将标签替换为空

    s = """<div>
    <p>岗位职责:</p>
    <p>完成推荐算法、数据统计、接口、后台等服务器端相关工作</p>
    <p><br></p>
    <P>必备要求:</p>
    <p>良好的自我驱动力和职业素养,工作积极主动、结果导向</p>
    <p>&nbsp;<br></p>
    <p>技术要求:</p>
    <p>1、一年以上 Python开发经验,掌握面向对象分析和设计,了解设计模式</p>
    <p>2、掌握HTTP协议,熟悉NVC、MVVM等概念以及相关wEB开发框架</p>
    <p>3、掌握关系数据库开发设计,掌握SQL,熟练使用 MySQL/PostgresQL中的一种<br></p>
    <p>4、掌握NoSQL、MQ,熟练使用对应技术解决方案</p>
    <p>5、熟悉 Javascript/cSS/HTML5,JQuery,React.Vue.js</p>
    <p>&nbsp;<br></p>
    <p>加分项:</p>
    <p>大数据,数理统计,机器学习,sklearn,高性能,大并发。</p>
    </div>"""

    要提取出来最重要的就是关闭贪婪模式,

    result = re.sub(r'<.*?>|&nbsp','',s)  #
    print(result)

     如果关闭贪婪模式,<xx>中的内容会尽可能多的匹配,只要能够满足后面的>就行,然后<>xxx<>中xxx内容也替换掉了

     提取图片地址

    import re
    s = """<img data-original="https://img02.sogoucdn.com/app/a/100520024/36189693dc8db6bd7c0be389f8aaddbd.jpg" src="https://img02.sogoucdn.com/app/a/100520024/36189693dc8db6bd7c0be389f8aaddbd.jpg" width="250" height="375" .jpg>"""
    result1 = re.search(r"src=\"https.*.jpg\"",s)   
    print(result1.group())
    
    result2 = re.search(r"src=\"(https.*.jpg)\"",s) #我只是想将网址提取出来,所以httpxx加括号,这样我就可以把它单独提取出来,src则不会出来
    print(result2.groups()[0])

    展开全文
  • 正则表达式是一个很强大的字符串处理工具,几乎任何关于字符串的操作都可以使用正则表达式来完成,作为一个爬虫工作者,每天和字符串打交道,正则表达式更是不可或缺的技能,正则表达式的在不同的语言中使用方式可能...

    转自:https://www.cnblogs.com/dyfblog/p/5880728.html

    Mark一下,以后学习使用备份。

    正则表达式是一个很强大的字符串处理工具,几乎任何关于字符串的操作都可以使用正则表达式来完成,作为一个爬虫工作者,每天和字符串打交道,正则表达式更是不可或缺的技能,正则表达式的在不同的语言中使用方式可能不一样,不过只要学会了任意一门语言的正则表达式用法,其他语言中大部分也只是换了个函数的名称而已,本质都是一样的。下面,我来介绍一下python中的正则表达式是怎么使用的。

    首先,python中的正则表达式大致分为以下几部分:

    元字符

    模式

    函数

    re 内置对象用法

    分组用法

    环视用法

    所有关于正则表达式的操作都使用 python 标准库中的 re 模块。

    一、元字符 (参见 python 模块 re 文档)

    .                    匹配任意字符(不包括换行符)

    ^                    匹配开始位置,多行模式下匹配每一行的开始

    $                    匹配结束位置,多行模式下匹配每一行的结束

    *                    匹配前一个元字符0到多次

    +                    匹配前一个元字符1到多次

    ?                    匹配前一个元字符0到1次

    {m,n}                匹配前一个元字符m到n次

    \\                   转义字符,跟在其后的字符将失去作为特殊元字符的含义,例如\\.只能匹配.,不能再匹配任意字符

    []                   字符集,一个字符的集合,可匹配其中任意一个字符

    |                    逻辑表达式 或 ,比如 a|b 代表可匹配 a 或者 b

    (...)                分组,默认为捕获,即被分组的内容可以被单独取出,默认每个分组有个索引,从 1 开始,按照"("的顺序决定索引值

    (?iLmsux)            分组中可以设置模式,iLmsux之中的每个字符代表一个模式,用法参见 模式 I

    (?:...)              分组的不捕获模式,计算索引时会跳过这个分组

    (?P...)        分组的命名模式,取此分组中的内容时可以使用索引也可以使用name

    (?P=name)            分组的引用模式,可在同一个正则表达式用引用前面命名过的正则

    (?#...)              注释,不影响正则表达式其它部分,用法参见 模式 I

    (?=...)              顺序肯定环视,表示所在位置右侧能够匹配括号内正则

    (?!...)              顺序否定环视,表示所在位置右侧不能匹配括号内正则

    (?<=...)             逆序肯定环视,表示所在位置左侧能够匹配括号内正则

    (?

    (?(id/name)yes|no)   若前面指定id或name的分区匹配成功则执行yes处的正则,否则执行no处的正则

    \number              匹配和前面索引为number的分组捕获到的内容一样的字符串

    \A                   匹配字符串开始位置,忽略多行模式

    \Z                   匹配字符串结束位置,忽略多行模式

    \b                   匹配位于单词开始或结束位置的空字符串

    \B                   匹配不位于单词开始或结束位置的空字符串

    \d                   匹配一个数字, 相当于 [0-9]

    \D                   匹配非数字,相当于 [^0-9]

    \s                   匹配任意空白字符, 相当于 [ \t\n\r\f\v]

    \S                   匹配非空白字符,相当于 [^ \t\n\r\f\v]

    \w                   匹配数字、字母、下划线中任意一个字符, 相当于 [a-zA-Z0-9_]

    \W                   匹配非数字、字母、下划线中的任意字符,相当于 [^a-zA-Z0-9_]

    二、模式

    I    IGNORECASE, 忽略大小写的匹配模式, 样例如下

    s = 'hello World!'

    regex = re.compile("hello world!", re.I)

    print regex.match(s).group()

    #output> 'Hello World!'

    #在正则表达式中指定模式以及注释

    regex = re.compile("(?#注释)(?i)hello world!")

    print regex.match(s).group()

    #output> 'Hello World!'

    L    LOCALE, 字符集本地化。这个功能是为了支持多语言版本的字符集使用环境的,比如在转义符\w,在英文环境下,它代表[a-zA-Z0-9_],即所以英文字符和数字。如果在一个法语环境下使用,缺省设置下,不能匹配"é" 或   "ç"。加上这L选项和就可以匹配了。不过这个对于中文环境似乎没有什么用,它仍然不能匹配中文字符。

    M    MULTILINE,多行模式, 改变 ^ 和 $ 的行为

    s = '''first line

    second line

    third line'''

    # ^

    regex_start = re.compile("^\w+")

    print regex_start.findall(s)

    # output> ['first']

    regex_start_m = re.compile("^\w+", re.M)

    print regex_start_m.findall(s)

    # output> ['first', 'second', 'third']

    #$

    regex_end = re.compile("\w+$")

    print regex_end.findall(s)

    # output> ['line']

    regex_end_m = re.compile("\w+$", re.M)

    print regex_end_m.findall(s)

    # output> ['line', 'line', 'line']

    S   DOTALL,此模式下 '.' 的匹配不受限制,可匹配任何字符,包括换行符

    s = '''first line

    second line

    third line'''

    #

    regex = re.compile(".+")

    print regex.findall(s)

    # output> ['first line', 'second line', 'third line']

    # re.S

    regex_dotall = re.compile(".+", re.S)

    print regex_dotall.findall(s)

    # output> ['first line\nsecond line\nthird line']

    X    VERBOSE,冗余模式, 此模式忽略正则表达式中的空白和#号的注释,例如写一个匹配邮箱的正则表达式

    email_regex = re.compile("[\w+\.]+@[a-zA-Z\d]+\.(com|cn)")

    email_regex = re.compile("""[\w+\.]+ # 匹配@符前的部分

    @ # @符

    [a-zA-Z\d]+ # 邮箱类别

    \.(com|cn) # 邮箱后缀 """, re.X)

    U    UNICODE,使用 \w, \W, \b, \B 这些元字符时将按照 UNICODE 定义的属性.

    正则表达式的模式是可以同时使用多个的,在 python 里面使用按位或运算符 | 同时添加多个模式

    如 re.compile('', re.I|re.M|re.S)

    每个模式在 re 模块中其实就是不同的数字

    print re.I

    # output> 2

    print re.L

    # output> 4

    print re.M

    # output> 8

    print re.S

    # output> 16

    print re.X

    # output> 64

    print re.U

    # output> 32

    三、函数 (参见 python 模块 re 文档)

    python 的 re 模块提供了很多方便的函数使你可以使用正则表达式来操作字符串,每种函数都有它自己的特性和使用场景,熟悉之后对你的工作会有很大帮助

    compile(pattern, flags=0)

    给定一个正则表达式 pattern,指定使用的模式 flags 默认为0 即不使用任何模式,然后会返回一个 SRE_Pattern (参见 第四小节 re 内置对象用法) 对象

    regex = re.compile(".+")

    print regex

    # output> <_sre.sre_pattern object at>

    这个对象可以调用其他函数来完成匹配,一般来说推荐使用 compile 函数预编译出一个正则模式之后再去使用,这样在后面的代码中可以很方便的复用它,当然大部分函数也可以不用 compile 直接使用,具体见 findall 函数

    s = '''first line

    second line

    third line'''

    #

    regex = re.compile(".+")

    # 调用 findall 函数

    print regex.findall(s)

    # output> ['first line', 'second line', 'third line']

    # 调用 search 函数

    print regex.search(s).group()

    # output> first lin

    escape(pattern)

    转义 如果你需要操作的文本中含有正则的元字符,你在写正则的时候需要将元字符加上反斜扛 \ 去匹配自身, 而当这样的字符很多时,写出来的正则表达式就看起来很乱而且写起来也挺麻烦的,这个时候你可以使用这个函数,用法如下

    s = ".+\d123"

    #

    regex_str = re.escape(".+\d123")

    # 查看转义后的字符

    print regex_str

    # output> \.\+\\d123

    # 查看匹配到的结果

    for g in re.findall(regex_str, s):

    print g

    # output> .+\d123

    findall(pattern, string, flags=0)

    参数 pattern 为正则表达式, string 为待操作字符串, flags 为所用模式,函数作用为在待操作字符串中寻找所有匹配正则表达式的字串,返回一个列表,如果没有匹配到任何子串,返回一个空列表。

    s = '''first line

    second line

    third line'''

    # compile 预编译后使用 findall

    regex = re.compile("\w+")

    print regex.findall(s)

    # output> ['first', 'line', 'second', 'line', 'third', 'line']

    # 不使用 compile 直接使用 findall

    print re.findall("\w+", s)

    # output> ['first', 'line', 'second', 'line', 'third', 'line']

    finditer(pattern, string, flags=0)

    参数和作用与 findall 一样,不同之处在于 findall 返回一个列表, finditer 返回一个迭代器(参见http://www.cnblogs.com/huxi/archive/2011/07/01/2095931.html ), 而且迭代器每次返回的值并不是字符串,而是一个 SRE_Match (参见 第四小节 re 内置对象用法) 对象,这个对象的具体用法见 match 函数。

    s = '''first line

    second line

    third line'''

    regex = re.compile("\w+")

    print regex.finditer(s)

    # output>

    for i in regex.finditer(s):

    print i

    # output> <_sre.sre_match object at>

    # <_sre.sre_match object at>

    # <_sre.sre_match object at>

    # <_sre.sre_match object at>

    # <_sre.sre_match object at>

    # <_sre.sre_match object at>

    match(pattern, string, flags=0)

    使用指定正则去待操作字符串中寻找可以匹配的子串, 返回匹配上的第一个字串,并且不再继续找,需要注意的是 match 函数是从字符串开始处开始查找的,如果开始处不匹配,则不再继续寻找,返回值为 一个 SRE_Match (参见 第四小节 re 内置对象用法)对象,找不到时返回 None

    s = '''first line

    second line

    third line'''

    # compile

    regex = re.compile("\w+")

    m = regex.match(s)

    print m

    # output> <_sre.sre_match object at>

    print m.group()

    # output> first

    # s 的开头是 "f", 但正则中限制了开始为 i 所以找不到

    regex = re.compile("^i\w+")

    print regex.match(s)

    # output> None

    purge()

    当你在程序中使用 re 模块,无论是先使用 compile 还是直接使用比如 findall 来使用正则表达式操作文本,re 模块都会将正则表达式先编译一下, 并且会将编译过后的正则表达式放到缓存中,这样下次使用同样的正则表达式的时候就不需要再次编译, 因为编译其实是很费时的,这样可以提升效率,而默认缓存的正则表达式的个数是 100, 当你需要频繁使用少量正则表达式的时候,缓存可以提升效率,而使用的正则表达式过多时,缓存带来的优势就不明显了 (参考 《python re.compile对性能的影响》http://blog.trytofix.com/article/detail/13/), 这个函数的作用是清除缓存中的正则表达式,可能在你需要优化占用内存的时候会用到。

    search(pattern, string, flags=0)

    函数类似于 match,不同之处在于不限制正则表达式的开始匹配位置

    s = '''first line

    second line

    third line'''

    # 需要从开始处匹配 所以匹配不到

    print re.match('i\w+', s)

    # output> None

    # 没有限制起始匹配位置

    print re.search('i\w+', s)

    # output> <_sre.sre_match object at>

    print re.search('i\w+', s).group()

    # output> irst

    split(pattern, string, maxsplit=0, flags=0)

    参数 maxsplit 指定切分次数, 函数使用给定正则表达式寻找切分字符串位置,返回包含切分后子串的列表,如果匹配不到,则返回包含原字符串的一个列表

    s = '''first 111 line

    second 222 line

    third 333 line'''

    # 按照数字切分

    print re.split('\d+', s)

    # output> ['first ', ' line\nsecond ', ' line\nthird ', ' line']

    # \.+ 匹配不到 返回包含自身的列表

    print re.split('\.+', s, 1)

    # output> ['first 111 line\nsecond 222 line\nthird 333 line']

    # maxsplit 参数

    print re.split('\d+', s, 1)

    # output> ['first ', ' line\nsecond 222 line\nthird 333 line']

    sub(pattern, repl, string, count=0, flags=0)

    替换函数,将正则表达式 pattern 匹配到的字符串替换为 repl 指定的字符串,  参数 count 用于指定最大替换次数

    s = "the sum of 7 and 9 is [7+9]."

    # 基本用法 将目标替换为固定字符串

    print re.sub('\[7\+9\]', '16', s)

    # output> the sum of 7 and 9 is 16.

    # 高级用法 1 使用前面匹配的到的内容 \1 代表 pattern 中捕获到的第一个分组的内容

    print re.sub('\[(7)\+(9)\]', r'\2\1', s)

    # output> the sum of 7 and 9 is 97.

    # 高级用法 2 使用函数型 repl 参数, 处理匹配到的 SRE_Match 对象

    def replacement(m):

    p_str = m.group()

    if p_str == '7':

    return '77'

    if p_str == '9':

    return '99'

    return ''

    print re.sub('\d', replacement, s)

    # output> the sum of 77 and 99 is [77+99].

    # 高级用法 3 使用函数型 repl 参数, 处理匹配到的 SRE_Match 对象 增加作用域 自动计算

    scope = {}

    example_string_1 = "the sum of 7 and 9 is [7+9]."

    example_string_2 = "[name = 'Mr.Gumby']Hello,[name]"

    def replacement(m):

    code = m.group(1)

    st = ''

    try:

    st = str(eval(code, scope))

    except SyntaxError:

    exec code in scope

    return st

    # 解析: code='7+9'

    # str(eval(code, scope))='16'

    print re.sub('\[(.+?)\]', replacement, example_string_1)

    # output> the sum of 7 and 9 is 16.

    # 两次替换

    # 解析1: code="name = 'Mr.Gumby'"

    # eval(code)

    # raise SyntaxError

    # exec code in scope

    # 在命名空间 scope 中将 "Mr.Gumby" 赋给了变量 name

    # 解析2: code="name"

    # eval(name) 返回变量 name 的值 Mr.Gumby

    print re.sub('\[(.+?)\]', replacement, example_string_2)

    # output> Hello,Mr.Gumby

    subn(pattern, repl, string, count=0, flags=0)

    作用与函数 sub 一样, 唯一不同之处在于返回值为一个元组,第一个值为替换后的字符串,第二个值为发生替换的次数

    template(pattern, flags=0)

    这个吧,咋一看和 compile 差不多,不过不支持 +、?、*、{} 等这样的元字符,只要是需要有重复功能的元字符,就不支持,查了查资料,貌似没人知道这个函数到底是干嘛的...

    四、re 内置对象用法

    SRE_Pattern    这个对象是一个编译后的正则表达式,编译后不仅能够复用和提升效率,同时也能够获得一些其他的关于正则表达式的信息

    属性:

    flags         编译时指定的模式

    groupindex    以正则表达式中有别名的组的别名为键、以该组对应的编号为值的字典,没有别名的组不包含在内。

    groups        正则表达式中分组的数量

    pattern       编译时用的正则表达式

    s = 'Hello, Mr.Gumby : 2016/10/26'

    p = re.compile('''(?: # 构造一个不捕获分组 用于使用 |

    (?P\w+\.\w+) # 匹配 Mr.Gumby

    | # 或

    (?P\s+\.\w+) # 一个匹配不到的命名分组

    )

    .*? # 匹配 :

    (\d+) # 匹配 2016

    ''', re.X)

    #

    print p.flags

    # output> 64

    print p.groupindex

    # output> {'name': 1, 'no': 2}

    print p.groups

    # output> 3

    print p.pattern

    # output> (?: # 构造一个不捕获分组 用于使用 |

    # (?P\w+\.\w+) # 匹配 Mr.Gumby

    # | # 或

    # (?P\s+\.\w+) # 一个匹配不到的命名分组

    # )

    # .*? # 匹配 :

    # (\d+) # 匹配 2016

    函数:可使用 findall、finditer、match、search、split、sub、subn 等函数

    SRE_Match    这个对象会保存本次匹配的结果,包含很多关于匹配过程以及匹配结果的信息

    属性:

    endpos       本次搜索结束位置索引

    lastgroup    本次搜索匹配到的最后一个分组的别名

    lastindex    本次搜索匹配到的最后一个分组的索引

    pos          本次搜索开始位置索引

    re           本次搜索使用的 SRE_Pattern 对象

    regs         列表,元素为元组,包含本次搜索匹配到的所有分组的起止位置

    string       本次搜索操作的字符串

    s = 'Hello, Mr.Gumby : 2016/10/26'

    m = re.search(', (?P\w+\.\w+).*?(\d+)', s)

    # 本次搜索的结束位置索引

    print m.endpos

    # output> 28

    # 本次搜索匹配到的最后一个分组的别名

    # 本次匹配最后一个分组没有别名

    print m.lastgroup

    # output> None

    # 本次搜索匹配到的最后一个分组的索引

    print m.lastindex

    # output> 2

    # 本次搜索开始位置索引

    print m.pos

    # output> 0

    # 本次搜索使用的 SRE_Pattern 对象

    print m.re

    # output> <_sre.sre_pattern object at>

    # 列表,元素为元组,包含本次搜索匹配到的所有分组的起止位置 第一个元组为正则表达式匹配范围

    print m.regs

    # output> ((7, 22), (7, 15), (18, 22))

    # 本次搜索操作的字符串

    print m.string

    # output> Hello, Mr.Gumby : 2016/10/26

    函数:

    end([group=0])               返回指定分组的结束位置,默认返回正则表达式所匹配到的最后一个字符的索引

    expand(template)             根据模版返回相应的字符串,类似与 sub 函数里面的 repl, 可使用 \1 或者 \g 来选择分组

    group([group1, ...])         根据提供的索引或名字返回响应分组的内容,默认返回 start() 到 end() 之间的字符串, 提供多个参数将返回一个元组

    groupdict([default=None])    返回 返回一个包含所有匹配到的命名分组的字典,没有命名的分组不包含在内,key 为组名, value 为匹配到的内容,参数 default 为没有参与本次匹配的命名分组提供默认值

    groups([default=None])       以元组形式返回每一个分组匹配到的字符串,包括没有参与匹配的分组,其值为 default

    span([group])                返回指定分组的起止位置组成的元组,默认返回由 start() 和 end() 组成的元组

    start([group])               返回指定分组的开始位置,默认返回正则表达式所匹配到的第一个字符的索引

    s = 'Hello, Mr.Gumby : 2016/10/26'

    m = re.search('''(?: # 构造一个不捕获分组 用于使用 |

    (?P\w+\.\w+) # 匹配 Mr.Gumby

    | # 或

    (?P\s+\.\w+) # 一个匹配不到的命名分组

    )

    .*? # 匹配 :

    (\d+) # 匹配 2016

    ''',

    s, re.X)

    # 返回指定分组的结束位置,默认返回正则表达式所匹配到的最后一个字符的索引

    print m.end()

    # output> 22

    # 根据模版返回相应的字符串,类似与 sub 函数里面的 repl, 可使用 \1 或者 \g 来选择分组

    print m.expand("my name is \\1")

    # output> my name is Mr.Gumby

    # 根据提供的索引或名字返回响应分组的内容,默认返回 start() 到 end() 之间的字符串, 提供多个参数将返回一个元组

    print m.group()

    # output> Mr.Gumby : 2016

    print m.group(1,2)

    # output> ('Mr.Gumby', None)

    # 返回 返回一个包含所有匹配到的命名分组的字典,没有命名的分组不包含在内,key 为组名, value 为匹配到的内容,参数 default 为没有参与本次匹配的命名分组提供默认值

    print m.groupdict('default_string')

    # output> {'name': 'Mr.Gumby', 'no': 'default_string'}

    # 以元组形式返回每一个分组匹配到的字符串,包括没有参与匹配的分组,其值为 default

    print m.groups('default_string')

    # output> ('Mr.Gumby', 'default_string', '2016')

    # 返回指定分组的起止未知组成的元组,默认返回由 start() 和 end() 组成的元组

    print m.span(3)

    # output> (18, 22)

    # 返回指定分组的开始位置,默认返回正则表达式所匹配到的第一个字符的索引

    print m.start(3)

    # output> 18

    五、分组用法

    python 的正则表达式中用小括号 "(" 表示分组,按照每个分组中前半部分出现的顺序 "(" 判定分组的索引,索引从 1 开始,每个分组在访问的时候可以使用索引,也可以使用别名

    s = 'Hello, Mr.Gumby : 2016/10/26'

    p = re.compile("(?P\w+\.\w+).*?(\d+)(?#comment)")

    m = p.search(s)

    # 使用别名访问

    print m.group('name')

    # output> Mr.Gumby

    # 使用分组访问

    print m.group(2)

    # output> 2016

    有时候可能只是为了把正则表达式分组,而不需要捕获其中的内容,这时候可以使用非捕获分组

    s = 'Hello, Mr.Gumby : 2016/10/26'

    p = re.compile("""

    (?: # 非捕获分组标志 用于使用 |

    (?P\w+\.\w+)

    |

    (\d+/)

    )

    """, re.X)

    m = p.search(s)

    # 使用非捕获分组

    # 此分组将不计入 SRE_Pattern 的 分组计数

    print p.groups

    # output> 2

    # 不计入 SRE_Match 的分组

    print m.groups()

    # output> ('Mr.Gumby', None)

    如果你在写正则的时候需要在正则里面重复书写某个表达式,那么你可以使用正则的引用分组功能,需要注意的是引用的不是前面分组的 正则表达式而是捕获到的 内容,并且引用的分组不算在分组总数中.

    s = 'Hello, Mr.Gumby : 2016/2016/26'

    p = re.compile("""

    (?: # 非捕获分组标志 用于使用 |

    (?P\w+\.\w+)

    |

    (\d+/)

    )

    .*?(?P\d+)/(?P=number)/

    """, re.X)

    m = p.search(s)

    # 使用引用分组

    # 此分组将不计入 SRE_Pattern 的 分组计数

    print p.groups

    # output> 3

    # 不计入 SRE_Match 的分组

    print m.groups()

    # output> ('Mr.Gumby', None, '2016')

    # 查看匹配到的字符串

    print m.group()

    # output> Mr.Gumby : 2016/2016/

    六、环视用法

    环视还有其他的名字,例如 界定、断言、预搜索等,叫法不一。

    环视是一种特殊的正则语法,它匹配的不是字符串,而是 位置,其实就是使用正则来说明这个位置的左右应该是什么或者应该不是什么,然后去寻找这个位置。

    环视的语法有四种,见第一小节元字符,基本用法如下。

    s = 'Hello, Mr.Gumby : 2016/10/26 Hello,r.Gumby : 2016/10/26'

    # 不加环视限定

    print re.compile("(?P\w+\.\w+)").findall(s)

    # output> ['Mr.Gumby', 'r.Gumby']

    # 环视表达式所在位置 左边为 "Hello, "

    print re.compile("(?<=Hello, )(?P\w+\.\w+)").findall(s)

    # output> ['Mr.Gumby']

    # 环视表达式所在位置 左边不为 ","

    print re.compile("(?\w+\.\w+)").findall(s)

    # output> ['Mr.Gumby']

    # 环视表达式所在位置 右边为 "M"

    print re.compile("(?=M)(?P\w+\.\w+)").findall(s)

    # output> ['Mr.Gumby']

    # 环视表达式所在位置 右边不为 r

    print re.compile("(?!r)(?P\w+\.\w+)").findall(s)

    # output> ['Mr.Gumby']

    转自:https://www.cnblogs.com/dyfblog/p/5880728.html

    展开全文
  • 目前找到的关于python 正则表达式介绍最好最详细的文档,梳理得也很有条理!
  • Python正则表达式详解 (超详细,看完必会!)

    万次阅读 多人点赞 2020-03-28 14:02:26
    正则表达式详解 正则表达式 英文名称叫 Regular Expression简称RegEx,是用来匹配字符的一种工具,它常被用在网页爬虫,文稿整理,数据筛选等方面,最常用的就是用在网页爬虫,数据抓取。 一、正则表达式的各种符号...
  • 主要介绍了Python正则表达式分组概念与用法,结合具体实例形式较为详细的分析了Python正则表达式中分组、引用、断言等概念与相关使用技巧,需要的朋友可以参考下

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 14,432
精华内容 5,772
关键字:

python正则表达式详解

友情链接: elauje.rar