Python 正则表达式

本文详细介绍Python中的正则表达式应用,涵盖基础概念、特殊符号解析及re模块的使用技巧。通过具体示例,帮助读者掌握正则表达式的编写与匹配规则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Python正则表达式操作指南:https://wiki.ubuntu.org.cn/Python正则表达式操作指南
菜鸟教程 之 python 正则表达式:http://www.runoob.com/python/python-reg-expressions.html
python 官网正则文档:https://docs.python.org/zh-cn/3.13/library/re.html

1、正则表达式基础

1.1. 正则表达式 "语法、元字符"

正则表达式是用于处理字符串的强大工具,大部分编程语言都提供有正则处理字符串的功能。正则表达式的语法都是一样的,区别只在于不同的编程语言实现支持的语法数量不同。

下图展示了使用正则表达式进行匹配的流程: 

re_simple

正则表达式的大致匹配过程是:依次拿出表达式和文本中的字符比较,如果每一个字符都能匹配,则匹配成功;一旦有匹配不成功的字符则匹配失败。如果表达式中有量词或边界,这个过程会稍微有一些不同,但也是很好理解的,看下图中的示例以及自己多使用几次就能明白。

下图列出了 Python 支持的正则表达式元字符和语法:   

1.2. 数量词的 "贪婪、非贪婪"

正则表达式通常用于在文本中查找匹配的字符串。Python里数量词默认是贪婪的(在少数语言里也可能是默认非贪婪),总是尝试匹配尽可能多的字符;非贪婪的则相反,总是尝试匹配尽可能少的字符。

例如:正则表达式 "ab*" 如果用于查找 "abbbc",将找到"abbb"。

           而如果使用非贪婪的数量词"ab*?",将找到"a"。

示例:abc123def123ghi123

贪婪匹配

  • :abc.*?
  • :abc.*123

非贪婪匹配:adc.*?123

1.3. 转义字符 \

与大多数编程语言相同,正则表达式里使用"\"作为转义字符,这就可能造成反斜杠困扰。假如你需要匹配文本中的字符"\",那么使用编程语言表示的正则表达式里将需要4个反斜杠"\\\\":前两个和后两个分别用于在编程语言里转义成反斜杠,转换成两个反斜杠后再在正则表达式里转义成一个反斜杠。Python里的原生字符串很好地解决了这个问题,这个例子中的正则表达式可以使用r"\\"表示。同样,匹配一个数字的"\\d"可以写成r"\d"。有了原生字符串,你再也不用担心是不是漏写了反斜杠,写出来的表达式也更直观。

1.4. 匹配模式

正则表达式提供了一些可用的匹配模式,比如忽略大小写、多行匹配等

  • re.I (即 IGNORECASE):忽略大小写(括号内是完整写法,下同)
  • re.M (即 MULTILINE):多行模式,改变'^'和'$'的行为(参见上图)
  • re.S (即 DOTALL):点任意匹配模式,改变'.'的行为
  • re.L (即 LOCALE):使预定字符类 \w \W \b \B \s \S 取决于当前区域设定
  • re.U (即 UNICODE):使预定字符类 \w \W \b \B \s \S \d \D 取决于unicode定义的字符属性
  • re.X (即 VERBOSE):详细模式。这个模式下正则表达式可以是多行,忽略空白字符,并可以加入注释。

2、Python 的 re 模块

以下是正则表达式格式的简要说明。更详细的信息和演示,参考 正则表达式指南

  • .(点号.) 在默认模式下,匹配除换行符以外的任意字符。 如果指定了旗标 DOTALL,它将匹配包括换行符在内的任意字符。 (?s:.) 将匹配任意字符而无视相关旗标。
  • ^ (插入符) 匹配字符串的开头, 并且在 MULTILINE 模式下也匹配换行后的首个符号。
  • $ (美元符) 匹配字符串尾或者在字符串尾的换行符的前一个字符,在 MULTILINE 模式下也会匹配换行符之前的文本。 foo 匹配 'foo' 和 'foobar',但正则表达式 foo$ 只匹配 'foo'。 更有趣的是,在 'foo1\nfoo2\n' 中搜索 foo.$,通常匹配 'foo2',但在 MULTILINE 模式下可以匹配到 'foo1';在 'foo\n' 中搜索 $ 会找到两个(空的)匹配:一个在换行符之前,一个在字符串的末尾。
  • * (星号) 对它前面的正则式匹配0到任意次重复, 尽量多的匹配字符串。 ab* 会匹配 'a''ab',或者 'a' 后面跟随任意个 'b'
  • + (加号) 对它前面的正则式匹配1到任意次重复。 ab+ 会匹配 'a' 后面跟随1个以上到任意个 'b',它不会匹配 'a'
  • ? (问号) 对它前面的正则式匹配0到1次重复。 ab? 会匹配 'a' 或者 'ab'
  • *?+??? 是非贪婪匹配。 '*''+' 和 '?' 数量限定符都是 贪婪的;它们会匹配尽可能多的文本。 有时这种行为并不被需要;如果 RE <.*> 针对 '<a> b <c>' 进行匹配,它将匹配整个字符串,而不只是 '<a>'。 在数量限定符之后添加 ? 将使其以 非贪婪 或 最小 风格来执行匹配;也就是将匹配数量尽可能 少的 字符。 使用 RE <.*?> 将只匹配 '<a>'
  • *+++?+ 类似于 '*''+' 和 '?' 数量限定符,添加了 '+' 的形式也将匹配尽可能多的次数。 但是,不同于真正的贪婪型数量限定符,这些形式在之后的表达式匹配失败时不允许反向追溯。 这些形式被称为 占有型 数量限定符。 例如,a*a 将匹配 'aaaa' 因为 a* 将匹配所有的 4 个 'a',但是,当遇到最后一个 'a' 时,表达式将执行反向追溯以便最终 a* 最后变为匹配总计 3 个 'a',而第四个 'a' 将由最后一个 'a' 来匹配。 然而,当使用 a*+a 时如果要匹配 'aaaa'a*+ 将匹配所有的 4 个 'a',但是在最后一个 'a' 无法找到更多字符来匹配时,表达式将无法被反向追溯并将因此匹配失败。 x*+x++ 和 x?+ 分别等价于 (?>x*)(?>x+) 和 (?>x?)
  • {m} 对其之前的正则式指定匹配 m 个重复;少于 m 的话就会导致匹配失败。比如, a{6} 将匹配6个 'a' , 但是不能是5个。
  • {m,n} 对正则式进行 m 到 n 次匹配,在 m 和 n 之间取尽量多。 比如,a{3,5} 将匹配 3 到 5个 'a'。忽略 m 意为指定下界为0,忽略 n 指定上界为无限次。 比如 a{4,}b 将匹配 'aaaab' 或者1000个 'a' 尾随一个 'b',但不能匹配 'aaab'。逗号不能省略,否则无法辨别修饰符应该忽略哪个边界。
  • {m,n}? 将导致结果 RE 匹配之前 RE 的 m 至 n 次重复,尝试匹配尽可能 少的 重复次数。 这是之前数量限定符的非贪婪版本。 例如,在 6 个字符的字符串 'aaaaaa' 上,a{3,5} 将匹配 5 个 'a' 字符,而 a{3,5}? 将只匹配 3 个字符。
  • {m,n}+ 将导致结果 RE 匹配之前 RE 的 m 至 n 次重复,尝试匹配尽可能多的重复而 不会 建立任何反向追溯点。 这是上述数量限定符的占有型版本。 例如,在 6 个字符的字符串 'aaaaaa' 上,a{3,5}+aa 将尝试匹配 5 个 'a' 字符,然后,要求再有 2 个 'a',这将需要比可用的更多的字符因而会失败,而 a{3,5}aa 的匹配将使 a{3,5} 先捕获 5 个,然后通过反向追溯再匹配 4 个 'a',然后用模式中最后的 aa 来匹配最后的 2 个 'a'。 x{m,n}+ 就等同于 (?>x{m,n})
  • \ 转义特殊字符(允许你匹配 '*''?', 或者此类其他),或者表示一个特殊序列;特殊序列之后进行讨论。如果你没有使用原始字符串( r'raw' )来表达样式,要牢记Python也使用反斜杠作为转义序列;如果转义序列不被Python的分析器识别,反斜杠和字符才能出现在字符串中。如果Python可以识别这个序列,那么反斜杠就应该重复两次。这将导致理解障碍,所以高度推荐,就算是最简单的表达式,也要使用原始字符串。
  • | 示例:A|B 匹配 A 或者 B。A 和 B 可以是任意正则表达式。任意个正则表达式可以用 '|' 连接。它也可以在组合(见下列)内使用。扫描目标字符串时, '|' 分隔开的正则样式从左到右进行匹配。当一个样式完全匹配时,这个分支就被接受。意思就是,一旦 A 匹配成功, B 就不再进行匹配,即便它能产生一个更好的匹配。或者说,'|' 操作符绝不贪婪。 如果要匹配 '|' 字符,使用 \|, 或者把它包含在字符集里,比如 [|]
  •  (...) (组合),匹配括号内的任意正则表达式,并标识出组合的开始和结尾。匹配完成后,组合的内容可以被获取,并可以在之后用 \number 转义序列进行再次匹配,之后进行详细说明。要匹配字符 '(' 或者 ')', 用 \( 或 \), 或者把它们包含在字符集合里: [(][)]
  • \number  匹配数字代表的组合。每个括号是一个组合,组合从1开始编号。比如 (.+) \1 匹配 'the the' 或者 '55 55', 但不会匹配 'thethe' (注意组合后面的空格)。这个特殊序列只能用于匹配前面99个组合。如果 number 的第一个数位是0, 或者 number 是三个八进制数,它将不会被看作是一个组合,而是八进制的数字值。在 '[' 和 ']' 字符集合内,任何数字转义都被看作是字符。
  • \A  只匹配字符串开始。
  • \b  匹配空字符串,但只在单词开始或结尾的位置。 一个单词被定义为一个单词字符的序列。 注意在通常情况下,\b 被定义为 \w 和 \W 字符之间的边界(反之亦然),或是 \w 和字符串开始或结尾之间的边界。 这意味着 r'\bat\b' 将匹配 'at', 'at.', '(at)' 和 'as at ay' 但不匹配 'attempt' 或 'atlas'。
  • \B 匹配空字符串,但仅限于它 不在 单词的开头或结尾的情况。 这意味着 r'at\B' 将匹配 'athens', 'atom', 'attorney',但不匹配 'at', 'at.' 或 'at!'。 \B 与 \b 正相反,这样 Unicode (str) 模式中的单词类字符是 Unicode 字母数字或下划线,但这可以通过使用 ASCII 旗标来改变。 如果使用了 LOCALE 旗标则单词边界将根据当前语言区域来确定。
  • \d  匹配任意十进制数。等价于 [0-9]
  • \D  匹配不属于十进制数码的任意字符。 这与 \d 正相反。
  • \s  匹配空白字符。如果使用了 ASCII 旗标则匹配 [ \t\n\r\f\v]。
  • \S  匹配非空白字符。 与 \s 正相反。如果使用了 ASCII 旗标则匹配 [^ \t\n\r\f\v]
  • \w  匹配单词类字符;这包括所有 Unicode 字母、数字、以及下划线 (_)。等价于 [a-zA-Z0-9_]
    \W  匹配不属于单词类字符的任意字符。 与 \w 正相反。 等价于 [^a-zA-Z0-9_]
    \Z  只匹配字符串尾

[] 用于表示一个字符集合。在一个集合中:

  • 字符可以单独列出,比如 [amk] 匹配 'a', 'm', 或者 'k'
  • 可以表示字符范围,通过用 '-' 将两个字符连起来。比如 [a-z] 将匹配任何小写ASCII字符, [0-5][0-9] 将匹配从 00 到 59 的两位数字, [0-9A-Fa-f] 将匹配任何十六进制数位。 如果 - 进行了转义 (比如 [a\-z])或者它的位置在首位或者末尾(如 [-a] 或 [a-]),它就只表示普通字符 '-'
  • 特殊字符在集合中会失去其特殊意义。比如 [(+*)] 只会匹配这几个字面字符之一 '(''+''*', or ')'
  • 字符类如 \w 或者 \S (定义如下) 也在集合内被接受,不过它们可匹配的字符则依赖于所使用的 flags
  • 不在集合范围内的字符可以通过 取反 来进行匹配。如果集合首字符是 '^' ,所有  在集合内的字符将会被匹配,比如 [^5] 将匹配所有字符,除了 '5', [^^] 将匹配所有字符,除了 '^'^ 如果不在集合首位,就没有特殊含义。
  • 要在集合内匹配一个 ']' 字面值,可以在它前面加上反斜杠,或是将它放到集合的开头。 例如,[()[\]{}] 和 []()[{}] 都可以匹配右方括号,以及左方括号,花括号和圆括号。
  • Unicode Technical Standard #18 里的嵌套集合和集合操作支持可能在未来添加。这将会改变语法,所以为了帮助这个改变,一个 FutureWarning 将会在有多义的情况里被 raise,包含以下几种情况,集合由 '[' 开始,或者包含下列字符序列 '--''&&''~~', 和 '||'。为了避免警告,需要将它们用反斜杠转义。

(?…) 这是个扩展标记法 (一个 '?' 跟随 '(' 并无含义)。 '?' 后面的第一个字符决定了这个构建采用什么样的语法。这种扩展通常并不创建新的组合; (?P<name>...) 是唯一的例外。 以下是目前支持的扩展。

  • (?aiLmsux) (一个或多个来自 'a''i''L''m''s''u''x' 集合的字母。) 分组将与空字符串相匹配;这些字母将为整个正则表达式设置相应的旗标:(该旗标在 模块内容 中有介绍。) 这适用于当你希望将该旗标包括为正则表达式的一部分,而不是向 re.compile() 函数传入 flag 参数的情况。 旗标应当在表达式字符串的开头使用。
    re.A (仅限 ASCII 匹配)
    re.I (忽略大小写)
    re.L (依赖于语言区域)
    re.M (多行)
    re.S (点号匹配所有字符)
    re.U (Unicode 匹配)
    re.X  (详细)
  • (?:…) 正则括号的非捕获版本。 匹配在括号内的任何正则表达式,但该分组所匹配的子字符串 不能 在执行匹配后被获取或是之后在模式中被引用。
  • (?aiLmsux-imsx:…)(零个或多个来自 'a''i''L''m''s''u''x' 集合的字母,后面可以带 '-' 再跟一个或多个来自 'i''m''s''x' 集合的字母。) 字母 'a', 'L' 和 'u' 在用作内联旗标时是互斥的,所以它们不能相互组合或者带 '-'。 相反,当它们中的某一个出现于内联的分组时,它将覆盖外层分组中匹配的模式。 在 Unicode 模式中 (?a:...) 将切换至仅限 ASCII 匹配,而 (?u:...) 将切换至 Unicode 匹配(默认)。 在字节串模式中 (?L:...) 将切换为基于语言区域的匹配,而 (?a:...) 将切换为仅限 ASCII 匹配(默认)。 这种覆盖将只在内联分组范围内生效,而在分组之外将恢复为原始的匹配模式。
  • (?>...) 尝试匹配 ... 就像它是一个单独的正则表达式,如果匹配成功,则继续匹配在它之后的剩余表达式。 如果之后的表达式匹配失败,则栈只能回溯到 (?>...) 之前 的点,因为一旦退出,这个被称为 原子化分组 的表达式将会丢弃其自身所有的栈点位。 因此,(?>.*). 将永远不会匹配任何东西因为首先 .* 将匹配所有可能的字符,然后,由于没有任何剩余的字符可供匹配,最后的 . 将匹配失败。 由于原子化分组中没有保存任何栈点位,并且在它之前也没有任何栈点位,因此整个表达式将匹配失败。
  • (?P<name>…) 与常规的圆括号类似,但分组所匹配到了子字符串可通过符号分组名称 name 来访问。 分组名称必须是有效的 Python 标识符,并且在 bytes 模式中它们只能包含 ASCII 范围内的字节值。 每个分组名称在一个正则表达式中只能定义一次。 一个符号分组同时也是一个编号分组,就像这个分组没有被命名过一样。命名组合可以在三种上下文中引用。如果样式是 (?P<quote>['"]).*?(?P=quote) (也就是说,匹配单引号或者双引号括起来的字符串):

  • (?P=name) 反向引用一个命名组合;它匹配前面那个叫 name 的命名组中匹配到的串同样的字串。
  • (?#…) 注释;里面的内容会被忽略。
  • (?=…) 当 … 匹配时,匹配成功,但不消耗字符串中的任何字符。这个叫做 前视断言 (lookahead assertion)。比如, Isaac (?=Asimov) 将会匹配 'Isaac ' ,仅当其后紧跟 'Asimov' 。
  • (?!…) 当 … 不匹配时,匹配成功。这个叫 否定型前视断言 (negative lookahead assertion)。例如, Isaac (?!Asimov) 将会匹配 'Isaac ' ,仅当它后面 不是 'Asimov' 。
  • (?<=…) 如果 ... 的匹配内容出现在当前位置的左侧,则匹配。这叫做 肯定型后视断言 (positive lookbehind assertion)。 (?<=abc)def 将会在 'abcdef' 中找到一个匹配,因为后视会回退3个字符并检查内部表达式是否匹配。内部表达式(匹配的内容)必须是固定长度的,意思就是 abc 或 a|b 是允许的,但是 a* 和 a{3,4} 不可以。注意,以肯定型后视断言开头的正则表达式,匹配项一般不会位于搜索字符串的开头。很可能你应该使用 search() 函数,而不是 match() 函数
  • (?<!…) 如果 ... 的匹配内容没有出现在当前位置的左侧,则匹配。这个叫做 否定型后视断言 (negative lookbehind assertion)。类似于肯定型后视断言,内部表达式(匹配的内容)必须是固定长度的。以否定型后视断言开头的正则表达式,匹配项可能位于搜索字符串的开头。
  • (?(id/name)yes-pattern|no-pattern) 如果给定的 id 或 name 存在,将会尝试匹配 yes-pattern ,否则就尝试匹配 no-pattern,no-pattern 可选,也可以被忽略。比如, (<)?(\w+@\w+(?:\.\w+)+)(?(1)>|$) 是一个email样式匹配,将匹配 '<user@host.com>' 或 'user@host.com' ,但不会匹配 '<user@host.com' ,也不会匹配 'user@host.com>'。

re.函数

re 提供了模块级别的方法,这些方法等价于Pattern实例中相对应的方法,两者可以相互替代。模块级别的方法好处是少写一行 re.compile() 代码,缺点是无法复用编译后的 Pattern对象。escape (string) 方法用于将 string 中的正则表达式元字符如*/+/?等之前加上转义符再返回,在需要大量匹配元字符时有那么一点用。

Python 通过 re 模块提供对正则表达式的支持。有两种使用方式:

  • 方式 1:直接先将正则表达式的字符串编译为 Pattern 对象,然后使用 Pattern 对象处理文本并获得匹配结果(一个Match实例),最后使用Match实例获得信息,进行其他的操作。
            re.compile(string[,flag])     # 返回 pattern 对象。pattern 可以理解为一个匹配模式。
    示例:创建一个 正则表达式对象(Pattern 对象),再通过 正则表达式对象 去匹配。
    # encoding: UTF-8
    import re
     
    # 将正则表达式编译成Pattern对象
    pattern = re.compile(r'hello')
     
    # 使用Pattern匹配文本,获得匹配结果,无法匹配时将返回None
    match = pattern.match('hello world!')
     
    if match:
        # 使用Match获得分组信息
        print match.group()
    
    page_source = """this is test, hello world"""
    result = pattern.finditer()
    for item in result:
        name = item.group("name")
        dao = item.group("dao")
        print(name)
  • 方式 2:直接使用 re 相关函数。格式:re.findall( pattern, 要匹配的字符串) 。
    提示:findall 可以换成 re 支持的任何函数。以下为 re 支持的部分函数
            re.match(pattern, string[, flags])
            re.search(pattern, string[, flags])
            re.split(pattern, string[, maxsplit])
            re.findall(pattern, string[, flags])
            re.finditer(pattern, string[, flags])
            re.sub(pattern, repl, string[, count])
            re.subn(pattern, repl, string[, count])
    示例:直接使用 re 相关函数。
    import re
    line = "Cats are smarter than dogs"
    matchObj = re.match( r'(.*) are (.*?) .*', line, re.M|re.I)
    if matchObj:
        print "matchObj.group() : ", matchObj.group()
        print "matchObj.group(1) : ", matchObj.group(1)
        print "matchObj.group(2) : ", matchObj.group(2)
    else:
        print "No match!!"
    
    test_string = """
    <div>
        <div>
            <span class="title">黑客帝国</span>
        </div>
    </div>
    """
    
    result_1 = re.finditer(r'<div>.*?<span class="title">(?P<bie_name>.*?)</span>', test_string, re.S)
    print(result_1)
    for item in result_1:
        print(item.group("bie_name"))
    
    # re.S 表示匹配任何字符,包括换行
    result_2 = re.findall(r'<div>.*?<span class="title">(?P<pipei_name>.*?)</span>', test_string, re.S)
    print(result_2)
    
    result_3 = re.findall(r'<div>.*?<span class="title">(?P<bie_name>.*?)</span>', test_string)
    print(result_3)
    
    result_4 = re.findall(r'<div>[\S\s]*?<span class="title">(.*?)</span>', test_string)
    print(result_4)
    

re.match(pattern, string[, flags])

Match对象是一次匹配的结果,包含了很多关于此次匹配的信息,可以使用Match提供的可读属性或方法来获取这些信息。

属性:

  1. string: 匹配时使用的文本。
  2. re: 匹配时使用的Pattern对象。
  3. pos: 文本中正则表达式开始搜索的索引。值与Pattern.match()和Pattern.seach()方法的同名参数相同。
  4. endpos: 文本中正则表达式结束搜索的索引。值与Pattern.match()和Pattern.seach()方法的同名参数相同。
  5. lastindex: 最后一个被捕获的分组在文本中的索引。如果没有被捕获的分组,将为None。
  6. lastgroup: 最后一个被捕获的分组的别名。如果这个分组没有别名或者没有被捕获的分组,将为None。

方法:

  1. group([group1, …]): 
    获得一个或多个分组截获的字符串;指定多个参数时将以元组形式返回。group1可以使用编号也可以使用别名;编号0代表整个匹配的子串;不填写参数时,返回group(0);没有截获字符串的组返回None;截获了多次的组返回最后一次截获的子串。
  2. groups([default]): 
    以元组形式返回全部分组截获的字符串。相当于调用group(1,2,…last)。default表示没有截获字符串的组以这个值替代,默认为None。
  3. groupdict([default]): 
    返回以有别名的组的别名为键、以该组截获的子串为值的字典,没有别名的组不包含在内。default含义同上。
  4. start([group]): 
    返回指定的组截获的子串在string中的起始索引(子串第一个字符的索引)。group默认值为0。
  5. end([group]): 
    返回指定的组截获的子串在string中的结束索引(子串最后一个字符的索引+1)。group默认值为0。
  6. span([group]): 
    返回(start(group), end(group))。
  7. expand(template): 
    将匹配到的分组代入template中然后返回。template中可以使用\id或\g<id>、\g<name>引用分组,但不能使用编号0。\id与\g<id>是等价的;但\10将被认为是第10个分组,如果你想表达\1之后是字符'0',只能使用\g<1>0。
import re
m = re.match(r'(\w+) (\w+)(?P<sign>.*)', 'hello world!')
 
print "m.string:", m.string
print "m.re:", m.re
print "m.pos:", m.pos
print "m.endpos:", m.endpos
print "m.lastindex:", m.lastindex
print "m.lastgroup:", m.lastgroup
 
print "m.group(1,2):", m.group(1, 2)
print "m.groups():", m.groups()
print "m.groupdict():", m.groupdict()
print "m.start(2):", m.start(2)
print "m.end(2):", m.end(2)
print "m.span(2):", m.span(2)
print r"m.expand(r'\2 \1\3'):", m.expand(r'\2 \1\3')
 
### output ###
# m.string: hello world!
# m.re: <_sre.SRE_Pattern object at 0x016E1A38>
# m.pos: 0
# m.endpos: 12
# m.lastindex: 3
# m.lastgroup: sign
# m.group(1,2): ('hello', 'world')
# m.groups(): ('hello', 'world', '!')
# m.groupdict(): {'sign': '!'}
# m.start(2): 6
# m.end(2): 11
# m.span(2): (6, 11)
# m.expand(r'\2 \1\3'): world hello!

re.search(pattern, string[, flags])

re.match 与 re.search 的区别

  • re.match 只匹配 字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;即 re.match 自带 ^
  • re.search 匹配 整个字符串,直到找到一个匹配的
#!/usr/bin/env python
# -*- coding: UTF-8 -*-

import re

line = "Cats are smarter than dogs";
matchObj = re.match(r'dogs', line, re.M | re.I)
if matchObj:
    print "match --> matchObj.group() : ", matchObj.group()
else:
    print "No match!!"

matchObj = re.search(r'dogs', line, re.M | re.I)
if matchObj:
    print "search --> matchObj.group() : ", matchObj.group()
else:
    print "No match!!"

实例方法 [ | re模块方法]:

  1. match(string[, pos[, endpos]]) | re.match(pattern, string[, flags]): 
    这个方法将从string的pos下标处起尝试匹配pattern;如果pattern结束时仍可匹配,则返回一个Match对象;如果匹配过程中pattern无法匹配,或者匹配未结束就已到达endpos,则返回None。
    pos和endpos的默认值分别为0和len(string);re.match()无法指定这两个参数,参数flags用于编译pattern时指定匹配模式。 
    注意:这个方法并不是完全匹配。当pattern结束时若string还有剩余字符,仍然视为成功。想要完全匹配,可以在表达式末尾加上边界匹配符'$'。 
    示例参见2.1小节。
  2. search(string[, pos[, endpos]]) | re.search(pattern, string[, flags]):
    这个方法用于查找字符串中可以匹配成功的子串。从string的pos下标处起尝试匹配pattern,如果pattern结束时仍可匹配,则返回一个Match对象;若无法匹配,则将pos加1后重新尝试匹配;直到pos=endpos时仍无法匹配则返回None。
    pos和endpos的默认值分别为0和len(string));re.search()无法指定这两个参数,参数flags用于编译pattern时指定匹配模式。
# encoding: UTF-8 
import re 
 
# 将正则表达式编译成Pattern对象 
pattern = re.compile(r'world') 
 
# 使用search()查找匹配的子串,不存在能匹配的子串时将返回None 
# 这个例子中使用match()无法成功匹配 
match = pattern.search('hello world!') 
 
if match: 
    # 使用Match获得分组信息 
    print match.group() 
 
### 输出 ### 
# world

re.split(pattern, string[, maxsplit]):

按照能够匹配的子串将string分割后返回列表。maxsplit用于指定最大分割次数,不指定将全部分割。

import re
 
p = re.compile(r'\d+')
print p.split('one1two2three3four4')
 
### output ###
# ['one', 'two', 'three', 'four', '']

re.findall(pattern, string[, flags]):

搜索string,以列表形式返回全部能匹配的子串。

import re
 
p = re.compile(r'\d+')
print p.findall('one1two2three3four4')
 
### output ###
# ['1', '2', '3', '4']

re.finditer(pattern, string[, flags]):

搜索 string,返回一个顺序访问每一个匹配结果(Match对象)的迭代器。

import re
 
p = re.compile(r'\d+')
for m in p.finditer('one1two2three3four4'):
    print m.group(),
 
### output ###
# 1 2 3 4

re.sub(pattern, repl, string[, count]):

使用 repl 替换 string 中每一个匹配的子串后返回替换后的字符串。

  • 当 repl 是一个字符串时,可以使用 \id 或 \g、\g 引用分组,但不能使用编号0。
  • 当 repl 是一个方法时,这个方法应当只接受一个参数(Match对象),并返回一个字符串用于替换( 返回的字符串中不能再引用分组 )。
  • count 用于指定最多替换次数,不指定时全部替换。
import re
 
p = re.compile(r'(\w+) (\w+)')
s = 'i say, hello world!'
 
print p.sub(r'\2 \1', s)
 
def func(m):
    return m.group(1).title() + ' ' + m.group(2).title()
 
print p.sub(func, s)
 
### output ###
# say i, world hello!
# I Say, Hello World!
#!/usr/bin/env python
# -*- coding: UTF-8 -*-

import re

phone = "2004-959-559 # This is Phone Number"
# Delete Python-style comments
num = re.sub(r'#.*$', "", phone)
print "Phone Num : ", num
# Remove anything other than digits
num = re.sub(r'\D', "", phone)
print "Phone Num : ", num

# 执行结果如下:
# Phone Num : 2004-959-559
# Phone Num : 2004959559

re.subn(pattern, repl, string[, count]):

返回 ( sub(repl, string[, count]), 替换次数 )。

import re
 
p = re.compile(r'(\w+) (\w+)')
s = 'i say, hello world!'
 
print p.subn(r'\2 \1', s)
 
def func(m):
    return m.group(1).title() + ' ' + m.group(2).title()
 
print p.subn(func, s)
 
### output ###
# ('say i, world hello!', 2)
# ('I Say, Hello World!', 2)

正则表达式对象  (Pattern 对象)

正则表达式对象(Pattern) 不能直接实例化,必须使用 re.compile() 返回。re.compile 方法是 Pattern 类的工厂方法,用于将 字符串形式的正则表达式 编译为 Pattern对象。Pattern 对象其实就是一个已经编译好的正则表达式,可以通过 Pattern 提供的方法对文本进行匹配查找。

Pattern 提供了几个可读属性用于获取表达式的相关信息:

  1. pattern: 编译时用的表达式字符串。
  2. flags:编译时用的匹配模式。数字形式。取值可以使用按位或运算符'|'表示同时生效,比如re.I | re.M。另外,你也可以在regex字符串中指定模式,比如re.compile('pattern', re.I | re.M)与re.compile('(?im)pattern')是等价的。
    可选值有:
    re.I(re.IGNORECASE): 忽略大小写(括号内是完整写法,下同)
    re.M(MULTILINE): 多行模式,改变'^'和'$'的行为(参见上图)
    re.S(DOTALL): 点任意匹配模式,改变'.'的行为
    re.L(LOCALE): 使预定字符类 \w \W \b \B \s \S 取决于当前区域设定
    re.U(UNICODE): 使预定字符类 \w \W \b \B \s \S \d \D 取决于unicode定义的字符属性
    re.X(VERBOSE): 详细模式。这个模式下正则表达式可以是多行,忽略空白字符,并可以加入注释。以下两个正则表达式是等价的:
  3. groups: 表达式中分组的数量。
  4. groupindex: 以表达式中有别名的组的别名为键、以该组对应的编号为值的字典,没有别名的组不包含在内。
import re
p = re.compile(r'(\w+) (\w+)(?P<sign>.*)', re.DOTALL)
 
print "p.pattern:", p.pattern
print "p.flags:", p.flags
print "p.groups:", p.groups
print "p.groupindex:", p.groupindex
 
### output ###
# p.pattern: (\w+) (\w+)(?P<sign>.*)
# p.flags: 16
# p.groups: 3
# p.groupindex: {'sign': 3}

匹配对象

"匹配对象" 就是 match() 或者 search() 返回的对象。如果没有匹配到则返回 None。

内容概要:本文详细比较了GPU、TPU专用AI芯片在大模型推理优化方面的性能、成本及适用场景。GPU以其强大的并行计算能力和高带宽显存,适用于多种类型的神经网络模型和计算任务,尤其适合快速原型开发和边缘计算设备。TPU专为机器学习设计,擅长处理大规模矩阵运算密集型任务,如Transformer模型的推理,具有高吞吐量和低延迟特性,适用于自然语言处理和大规模数据中心的推理任务。专用AI芯片通过高度定制化架构,针对特定神经网络模型进行优化,如卷积神经网络(CNN),在处理特定任务时表现出色,同时具备低功耗和高能效比的优势,适用于边缘计算设备。文章还介绍了各自的优化工具和框架,如CUDA、TensorRT、TPU编译器等,并从硬件成本、运营成本和开发成本三个角度进行了成本对比。 适合人群:从事人工智能、深度学习领域的研究人员和技术人员,尤其是对大模型推理优化感兴趣的读者。 使用场景及目标:①帮助读者理解GPU、TPU和专用AI芯片在大模型推理中的优缺点;②为选择适合的硬件平台提供参考依据,以实现最优的推理性能和成本效益;③介绍各种优化工具和框架,帮助开发者高效部署和优化模型。 其他说明:本文不仅涵盖了硬件架构特性,还深入探讨了优化技术和应用场景,旨在为读者提供全面的技术参考。在选择硬件平台时,需综合考虑具体任务需求、预算限制及开发资源等因素。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值