常见问题

正则表达式是一个非常强大的工具,但在有些时候它并不能直观地按照你的意愿来运行。本篇我们将指出一些最常见的错误。

使用字符串方法

有时使用 re 模块是个错误!如果你匹配一个固定的字符串或者单个字符类,并且你没有使用 re 的任何标志(像 IGNORECASE 标志),那么就没有必要使用正则表达式了。字符串有一些方法是对固定字符串进行操作的,并且它们通常比较快。因为它们都是独立优化的 C 语言小循环,目的是在简单的情况下代替功能更加强大、更具通用性的正则表达式引擎。

举个例子,例如你想把字符串中所有的 dead 替换成 word,你会想到使用正则表达式的 re.sub() 方法来实现,但这么简单的替换,还是考虑直接使用字符串的 replace() 方法吧。但有一点你需要注意,就是 replace() 会在单词里边进行替换,像swordfish 会变成 sdeedfish,这显然不是你想要的!replace() 没办法识别单词的边界,因此你才来考虑使用正则表达式。只需要将 RE 的模式写成 \bword\b 即可胜任此任务。

另一个常见的情况是从一个字符串中删除单个字符或者用另一个字符替代它。你也许会想到用 re.sub('\n', ' ', S) 这样的正则表达式来实现,但其实字符的 translate() 方法完全能够胜任这个任务,并且比任何正则表达式操作起来更快些。
简而言之,在使用 re 模块之前,先考虑一下你的问题是否可以用更快速、简单的字符串自带方法来解决。

match() VS search()

match() 函数只会检查 RE 是否在字符串的开始处匹配,而 search() 会遍历整个字符串搜索匹配的内容。记住这一区别很重要。再次强调一下,match() 只会报告一次成功的匹配,并且匹配的位置必须是从字符串的第一个字符开始:

  1. >>> print(re.match('super', 'superstition').span())
  2. (0, 5)
  3. >>> print(re.match('super', 'insuperable'))
  4. None

复制代码

另一方面,search() 函数将遍历整个字符串,并报告它找到的第一个匹配:

  1. >>> print(re.search('super', 'superstition').span())
  2. (0, 5)
  3. >>> print(re.search('super', 'insuperable').span())
  4. (2, 7)

复制代码

有时候你可能会耍点小聪明,使用 re.match() 然后在 RE 的前边加上 .*。但尽量不要这么做,最好采用 re.search() 代替。正则表达式编译器会对 REs 做一些分析,以便可以在搜索匹配时提高速度。一般分析会先找到匹配的第一个字符是什么。举个例子,模式 Crow 必须从字符 'C' 开始匹配,那么匹配引擎分析后会快速遍历字符串,然后在 'C' 被找到之后才开始全部匹配。

按照上面的分析,你添加一个 .* 会导致这个优化失败,这就需要从头到尾扫描一遍,然后再回溯匹配 RE 剩余的部分。所以,请使用 re.search() 代替。

贪婪 VS 非贪婪

当重复一个正则表达式时,如果使用 a*,那么结果是尽可能多地去匹配。当你尝试匹配一对对称的定界符,例如 HTML 标志中的尖括号,默认的贪婪模式会使得你很困扰。

我们来看下例子:

  1. >>> s = '<html><head><title>Title</title>'
  2. >>> len(s)
  3. 32
  4. >>> print(re.match('<.*>', s).span())
  5. (0, 32)
  6. >>> print(re.match('<.*>', s).group())
  7. <html><head><title>Title</title>

复制代码

RE 匹配在 <html> 的 < 后,.* 消耗掉字符串的剩余部分。由于正则表达式默认是贪婪的原因,RE 必须从字符串的尾部一个字符一个字符地回溯,直到找到匹配的 >。大家看到,按照这种方法,最后找到匹配内容竟是 <html> 的 < 开始,到</title> 的 > 结束。显然这不是你想要的结果。

在这种情况下,解决方案是使用非贪婪的限定符 *?、+?、?? 或 {m, n}?,尽可能地匹配小的文本。

  1. >>> print(re.match('<.*?>', s).group())
  2. <html>

复制代码

在上边的例子中,> 在第一个 < 被匹配后立刻尝试匹配,如果失败,匹配引擎前进一步,尝试下一个字符,直到第一次匹配 >,这样就得到了我们想要的结果。

注意,使用正则表达式分析 HTML 和 XML 是很痛苦的。当你编写一个正则表达式去处理所有可能的情况时,你会发现 HTML 和 XML 总会打破你的“规则”,这让你很头疼......像这样的话,建议使用 HTML 和 XML 解析器来处理更合适。

使用 re.VERBOSE

现在你应该意识到了,正则表达式的表示非常紧凑。这也带来了一个问题,就是不好阅读。中等复杂的正则表达式可能包含许多反斜杠、圆括号和元字符,以至于难以读懂。

在这些 REs 中,当编译正则表达式时指定 re.VERBOSE 标志是非常有帮助的。因为它允许你可以编辑正则表达式的格式,使之更清楚。

re.VERBOSE 标志有几个作用。在正则表达式中不在字符类中的空白字符将被忽略。这就意味着像 I love FishC 这样的表达式和可读性较差的 IloveFishC 相同。但 [a b] 将匹配字符 'a'、'b' 或 ' ';另外,你也可以把注释放到 RE 中,注释是从 # 开始到下一行。当使用三引号字符串时,会使得 REs 的格式更整洁:

pat = re.compile(r"""
\s*                             # Skip leading whitespace
(?P<header>[^:]+)   # Header name
\s* :                           # Whitespace, and a colon
(?P<value>.*?)          # The header's value -- *? used to
                                  # lose the following trailing whitespace
\s*$                           # Trailing whitespace to end-of-line
""", re.VERBOSE)

同样的内容,下边这个要难读得多:

pat = re.compile(r"\s*(?P<header>[^:]+)\s*:(?P<value>.*?)\s*$")

<完>

Python3 如何优雅地使用正则表达式(详解七)的更多相关文章

  1. JavaScript正则表达式详解(一)正则表达式入门

    JavaScript正则表达式是很多JavaScript开发人员比较头疼的事情,也很多人不愿意学习,只是必要的时候上网查一下就可以啦~本文中详细的把JavaScript正则表达式的用法进行了列表,希望 ...

  2. JavaScript正则表达式详解(二)JavaScript中正则表达式函数详解

    二.JavaScript中正则表达式函数详解(exec, test, match, replace, search, split) 1.使用正则表达式的方法去匹配查找字符串 1.1. exec方法详解 ...

  3. Java 正则表达式详解_正则表达式

    body{ font-family: "Microsoft YaHei UI","Microsoft YaHei",SimSun,"Segoe UI& ...

  4. Django url配置 正则表达式详解 分组命名匹配 命名URL 别名 和URL反向解析 命名空间模式

    Django基础二之URL路由系统 本节目录 一 URL配置 二 正则表达式详解 三 分组命名匹配 四 命名URL(别名)和URL反向解析 五 命名空间模式 一 URL配置 Django 1.11版本 ...

  5. 【python3+request】python3+requests接口自动化测试框架实例详解教程

    转自:https://my.oschina.net/u/3041656/blog/820023 [python3+request]python3+requests接口自动化测试框架实例详解教程 前段时 ...

  6. (转)Python3.5——装饰器及应用详解

    原文:https://blog.csdn.net/loveliuzz/article/details/77853346 Python3.5——装饰器及应用详解(下)----https://blog.c ...

  7. (转)linux正则表达式详解

    linux正则表达式详解 http://blog.csdn.net/wuliowen/article/details/64131815 1:什么是正则表达式: 简单的说,正则表达式就是处理字符串的方法 ...

  8. Python3、setuptools、Pip3安装详解

    Python3.setuptools.Pip3安装详解 2017年08月19日 18:58:47 安静的技术控 阅读数:26002    版权声明:本文为博主原创文章,未经博主允许不得转载. http ...

  9. Linux文本处理三剑客之grep及正则表达式详解

    Linux文本处理三剑客之grep及正则表达式详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Linux文本处理三剑客概述 grep: 全称:"Global se ...

  10. Django路由配置之正则表达式详解

    正则表达式详解 urls.py from django.conf.urls import url from . import views urlpatterns = [ url(r'^articles ...

随机推荐

  1. Ultra-QuickSort(归并排序求逆序对数)

    Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 34283   Accepted: 12295 Description In ...

  2. (转载)PHP substr(),mb_substr()及mb_strcut的区别和用法

    (转载)http://blog.csdn.net/alongken2005/article/details/7098506 PHP substr()函数可以 分割文字,但要分割的文字如果包括中文字符往 ...

  3. bzoj2730 [HNOI2012]矿场搭建 (UVAlive5135 Mining Your Own Business)

    2730: [HNOI2012]矿场搭建 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1147  Solved: 528[Submit][Statu ...

  4. DLL入门浅析(4)——从DLL中导出类

    转载自:http://www.cppblog.com/suiaiguo/archive/2009/07/20/90663.html 前面介绍了怎么从DLL中导出函数和变量,实际上导出类的方法也是大同小 ...

  5. freemarker的非空判断

    ${price} 判断非空写法就是 ${(price)!}

  6. 总结工作中常用到的linux命令大全_经典

    常用解压命令 tar.bz2 命令: tar -jxvf  *.tar.bz2 tar.z   命令: tar -zxvf  *.tar.z tar.gz   命令: tar -Zxvf  *.tar ...

  7. maven + selenium + jenkins 教程收集

    maven + selenium + jenkins 教程收集 Complete Guide for Selenium integration with jenkins Maven http://le ...

  8. Web 前端 —— javaScript

    目录: 资源链接 基础知识 基础问题集 资源链接: http://www.w3school.com.cn/ 弹出窗口,变暗特效:http://www.csrcode.cn/article-584-1. ...

  9. Unity3D基础学习 NGUI之Example 13 - Tabs简要概述

    首先建一个2D相机,在Anchor下新建一个子物体,添加WindowDrag Tilt脚本,用作拖动窗口 然后新建一个Panel,包含两个content,两个Tab,设置两个Content用来显示切换 ...

  10. hduTHE MATRIX PROBLEM(差分约束)

    题目请戳这里 题目大意:给一个n*m的矩阵,求是否存在这样两个序列:a1,a2...an,b1,b2,...,bm,使得矩阵的第i行乘以ai,第j列除以bj后,矩阵的每一个数都在L和U之间. 题目分析 ...