常见问题

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

使用字符串方法

有时使用 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. SPFA 最短路径打印方法

    #include <iostream> #include <cstdlib> #include <cstdio> #include <algorithm> ...

  2. 【转】C#读取文件时的共享方式

    string sFileName = @"C:\Exchange.dat";System.IO.StreamReader file = new System.IO.StreamRe ...

  3. PHP IDE 框架 服务器 相关

    server:nginx  框架:一个比较老的项目用的ZendFramework,最近的新项目用的codeigniter  IDE:  zend studio  Sublime Text https: ...

  4. puppet常用调试命令

    yum快速部署puppet测试环境(C/S端) rpm -ivh  http://yum.puppetlabs.com/puppetlabs-release-el-7.noarch.rpm yum r ...

  5. [转载]Android开发必备的21个免费资源和工具

    转载自: http://blog.csdn.net/shimiso/article/details/6788375 Android移动开发平台现在不是一个“火”字能形容的,今年Android平台在市场 ...

  6. L - 还是畅通工程 - hdu 1233

    Description 某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离.省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达 ...

  7. C#中枚举类型和int类型的转化

    先定义一个枚举类型 , 初中, 高中,大学 }; int ->enum int d=2; PropertyType  a=(PropertyType)d; int <- enum Prop ...

  8. DHTML【6】--CSS

    从今天开始,我们迎来了一个新的面孔---CSS,二者这也是一个漂亮的面孔,为什么说这是一个漂亮的面孔呢?因为CSS是做特效的,可以美化HTML页面,我们看到淘宝网.网易首页等网站都非常好看,那都是一些 ...

  9. 错误 是否保存对以下各项的更改 devenv.sin

    描述: 打开VS2012项目时,提示 是否保存对以下各项的更改 devenv.sin google了一下,没找到...纠结.百度了一下,竟然有的...擦一直以为google很给力,看来对于中文的解析不 ...

  10. mysql数据库sql常用命令

    1.查看索引:mysql> show index from tblname; 2.利用索引查询:SELECT * FROM product WHERE ID > =(select id f ...