常见问题

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

使用字符串方法

有时使用 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. SQL 截图

  2. Selenium webdirver 操作浏览器

    打开浏览器 HtmlUnit Driver 优点:不会实际打开浏览器,运行速度很快. 缺点:对JavaScript的支持不够好,有时会捕获不到页面元素. 使用:WebDriver driver=new ...

  3. JQuery的ready函数与JS的onload的区别详解

    JQuery的ready函数与JS的onload的区别:1.执行时间window.onload必须等到页面内包括图片的所有元素加载完毕后才能执行.$(document).ready()是DOM结构绘制 ...

  4. WebView redirect https to http

    最新项目大改版,刚好对相关sdk版本做了下升级,target也从19升级到21. 意外发现原先在WebView中加载的网页中的图片全都变得一片白,连默认图片都不给显示. 经过一番测试才发现是由于tar ...

  5. ASSERT_VALID和ASSERT宏分析

    这个宏都是MFC的调试宏. ASSERT_VALID宏用来在运行时检查一个对象的内部合法性,比如说现在有一个学生对象,我们知道每个学生的年龄一定大于零,若年龄小于零,则该学生对象肯定有问题. 事实上, ...

  6. DELL R720服务器安装Windows Server 2008 R2 操作系统图文详解

    DELL R720服务器安装Windows Server 2008 R2 操作系统图文详解 说明:此文章中部分图片为网络搜集,所以不一定为DELL R720服务器安装界面,但可保证界面内容接近DELL ...

  7. apktool的下载地址

    googlecode将要关闭,代码转移到以下网址 http://ibotpeaches.github.io/Apktool/

  8. [Android]android.graphics.Camera实现图像的旋转、缩放,配合Matrix实现图像的倾斜

    android.graphics.Camera可以对图像执行一些比较复杂的操作,诸如旋转与绽放,与Matrix可实现图像的倾斜. 个人总结Camera与Matrix的一些区别如下: Camera的ro ...

  9. css01入门小例子

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  10. 富文本文件CKEDITOR增加上传图片功能(.net)

    如题,本身的CKEDITOR控件并没有开启上传图片的功能, 打开图像按钮,只有图像信息和高级两个table选项卡,版本不同,显示略有差异,我的实现是有两种方法都可以添加上传功能, 第一种方法使用CKE ...