Weibw's World Weibw's World
首页
  • HTML
  • Python

    • Python基础知识
    • Python CookBook第三版
    • Flask
  • MySQL

    • MySQL基础知识
    • MySQL调优
    • MySQL面试题
算法
  • FineReport
  • Kettle
  • Git
  • 微信公众号文章
  • 优秀博客文章
  • 其他
收藏夹
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Weibw

一个没有梦想的咸鱼
首页
  • HTML
  • Python

    • Python基础知识
    • Python CookBook第三版
    • Flask
  • MySQL

    • MySQL基础知识
    • MySQL调优
    • MySQL面试题
算法
  • FineReport
  • Kettle
  • Git
  • 微信公众号文章
  • 优秀博客文章
  • 其他
收藏夹
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 《Flask》

  • 《Python Cookbook》第三版

    • 第一章:数据结构与算法

    • 第二章:字符串和文本

      • 使用多个界定符分割字符串
      • 字符串开头或结尾匹配
      • 用 Shell 通配符匹配字符串
      • 字符串匹配和搜索
        • 字符串搜索和替换
        • 字符串忽略大小写的搜索替换
        • 最短匹配模式
        • 多行匹配模式
        • 将 Unicode 文本标准化
        • 在正则式中使用 Unicode
        • 删除字符串中不需要的字符
        • 审查清理文本字符串
        • 字符串对齐
        • 合并拼接字符串
        • 字符串中插入变量
        • 以指定列宽格式化字符串
        • 在字符串中处理html和xml
        • 字符串令牌解析
        • 实现一个简单的递归下降分析器
        • 字节字符串上的字符串操作
      • 第三章:数字日期和时间

      • 第四章:迭代器与生成器

      • 第五章:文件与IO

      • 第六章:数据编码和处理

      • 第七章:函数

      • 第八章:类与对象

      • 第九章:元编程

      • 第十章:模块与包

      • 第十一章:网络与Web编程

      • 第十二章:并发编程

      • 第十三章:脚本编程与系统管理

      • 第十四章:测试、调试和异常

      • 第十五章:C语言扩展

    • Python基础

    • Python
    • 《Python Cookbook》第三版
    • 第二章:字符串和文本
    weibw
    2021-12-22

    字符串匹配和搜索

    # 问题

    你想匹配或者搜索特定模式的文本

    # 解决方案

    如果你想匹配的是字面字符串,那么你通常只需要调用基本字符串方法就行,比如 str.find() , str.endswith() , str.startswith() 或者类似的方法:

    >>> text = 'yeah, but no, but yeah, but no, but yeah'
    >>> # Exact match
    >>> text == 'yeah'
    False
    >>> # Match at start or end
    >>> text.startswith('yeah')
    True
    >>> text.endswith('no')
    False
    >>> # Search for the location of the first occurrence
    >>> text.find('no')
    10
    >>>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    对于复杂的匹配需要使用正则表达式和 re 模块。为了解释正则表达式的基本原理, 假设你想匹配数字格式的日期字符串比如 11/27/2012 ,你可以这样做:

    >>> text1 = '11/27/2012'
    >>> text2 = 'Nov 27, 2012'
    >>>
    >>> import re
    >>> # Simple matching: \d+ means match one or more digits
    >>> if re.match(r'\d+/\d+/\d+', text1):
    ... print('yes')
    ... else:
    ... print('no')
    ...
    yes
    >>> if re.match(r'\d+/\d+/\d+', text2):
    ... print('yes')
    ... else:
    ... print('no')
    ...
    no
    >>>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18

    如果你想使用同一个模式去做多次匹配,你应该先将模式字符串预编译为模式对 象。比如:

    >>> datepat = re.compile(r'\d+/\d+/\d+')
    >>> if datepat.match(text1):
    ... 	print('yes')
    ... else:
    ... 	print('no')
    ...
    yes
    >>> if datepat.match(text2):
    ... 	print('yes')
    ... else:
    ... 	print('no')
    ...
    no
    >>>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

    match() 总是从字符串开始去匹配,如果你想查找字符串任意部分的模式出现位 置,使用 findall() 方法去代替。比如:

    >>> text = 'Today is 11/27/2012. PyCon starts 3/13/2013.'
    >>> datepat.findall(text)
    ['11/27/2012', '3/13/2013']
    >>>
    
    1
    2
    3
    4

    在定义正则式的时候,通常会利用括号去捕获分组。比如:

    >>> datepat = re.compile(r'(\d+)/(\d+)/(\d+)')
    >>>
    
    1
    2

    捕获分组可以使得后面的处理更加简单,因为可以分别将每个组的内容提取出来。 比如:

    >>> m = datepat.match('11/27/2012')
    >>> m
    <_sre.SRE_Match object at 0x1005d2750>
    >>> # Extract the contents of each group
    >>> m.group(0)
    '11/27/2012'
    >>> m.group(1)
    '11'
    >>> m.group(2)
    '27'
    >>> m.group(3)
    '2012'
    >>> m.groups()
    ('11', '27', '2012')
    >>> month, day, year = m.groups()
    >>>
    >>> # Find all matches (notice splitting into tuples)
    >>> text
    'Today is 11/27/2012. PyCon starts 3/13/2013.'
    >>> datepat.findall(text)
    [('11', '27', '2012'), ('3', '13', '2013')]
    >>> for month, day, year in datepat.findall(text):
    ... 	print('{}-{}-{}'.format(year, month, day))
    ...
    2012-11-27
    2013-3-13
    >>>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27

    findall() 方法会搜索文本并以列表形式返回所有的匹配。如果你想以迭代方式返 回匹配,可以使用 finditer() 方法来代替,比如:

    >>> for m in datepat.finditer(text):
    ... 	print(m.groups())
    ...
    ('11', '27', '2012')
    ('3', '13', '2013')
    >>>
    
    1
    2
    3
    4
    5
    6

    # 讨论

    关于正则表达式理论的教程已经超出了本书的范围。不过,这一节阐述了使用 re 模块进行匹配和搜索文本的最基本方法。核心步骤就是先使用 re.compile() 编译正则 表达式字符串,然后使用 match() , findall() 或者 finditer() 等方法。

    当写正则式字符串的时候,相对普遍的做法是使用原始字符串比如 r'(\d+)/ (\d+)/(\d+)' 。这种字符串将不去解析反斜杠,这在正则表达式中是很有用的。如果 不这样做的话,你必须使用两个反斜杠,类似 '(\d+)/(\d+)/(\d+)' 。

    需要注意的是 match() 方法仅仅检查字符串的开始部分。它的匹配结果有可能并 不是你期望的那样。比如:

    >>> m = datepat.match('11/27/2012abcdef')
    >>> m
    <_sre.SRE_Match object at 0x1005d27e8>
    >>> m.group()
    '11/27/2012'
    >>>
    
    1
    2
    3
    4
    5
    6

    如果你想精确匹配,确保你的正则表达式以 $ 结尾,就像这么这样:

    >>> datepat = re.compile(r'(\d+)/(\d+)/(\d+)$')
    >>> datepat.match('11/27/2012abcdef')
    >>> datepat.match('11/27/2012')
    <_sre.SRE_Match object at 0x1005d2750>
    >>>
    
    1
    2
    3
    4
    5

    最后,如果你仅仅是做一次简单的文本匹配/搜索操作的话,可以略过编译部分, 直接使用 re 模块级别的函数。比如:

    >>> re.findall(r'(\d+)/(\d+)/(\d+)', text)
    [('11', '27', '2012'), ('3', '13', '2013')]
    >>>
    
    1
    2
    3

    但是需要注意的是,如果你打算做大量的匹配和搜索操作的话,最好先编译正则表 达式,然后再重复使用它。模块级别的函数会将最近编译过的模式缓存起来,因此并不 会消耗太多的性能,但是如果使用预编译模式的话,你将会减少查找和一些额外的处理 损耗。

    编辑 (opens new window)
    #Python
    上次更新: 2023/10/13, 17:39:25
    用 Shell 通配符匹配字符串
    字符串搜索和替换

    ← 用 Shell 通配符匹配字符串 字符串搜索和替换→

    最近更新
    01
    牛客网非技术快速入门SQL练习题
    03-08
    02
    其他日常SQL题
    03-07
    03
    用户与权限管理
    03-05
    更多文章>
    Theme by Vdoing | Copyright © 2021-2023 | Weibw | 辽ICP备18015889号
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式