Python 中的 Perl 兼容正则表达式 (PCRE)

Posted

技术标签:

【中文标题】Python 中的 Perl 兼容正则表达式 (PCRE)【英文标题】:Perl compatible regular expression (PCRE) in Python 【发布时间】:2011-10-27 03:57:30 【问题描述】:

我必须在 Python 中基于 PCRE 解析一些字符串,我不知道该怎么做。

我要解析的字符串如下:

match mysql m/^.\0\0\0\n(4\.[-.\w]+)\0...\0/s p/MySQL/ i/$1/

在这个例子中,我必须得到这个不同的项目:

"m/^.\0\0\0\n(4\.[-.\w]+)\0...\0/s" ; "p/MySQL/" ; "i/$1/"

我发现的唯一与 Python 中的 PCRE 操作有关的是这个模块:http://pydoc.org/2.2.3/pcre.html(但它被写成一个 .so 文件......)

你知道是否存在一些 Python 模块来解析这种字符串吗?

【问题讨论】:

明确一点:您想匹配 PCRE,而不是使用它们? 好的,换句话说,您需要某人/某事将 PCRE 正则表达式翻译成 Python 正则表达式?看看RegexBuddy。 我正在寻找免费的东西 :) 是的,我正在寻找能够在 python 中翻译 PCRE 的东西。 Python 如何处理或无法处理正则表达式模式和字符串中的非 ASCII 存在一些非常微妙的问题,这些问题根据您使用的 Python 版本以及是否有一个“广泛的构建”。带有宽构建的 Python3 效果最好,带有窄构建的 Python2 效果最差,但它们都与 Perl 正则表达式 vis-à-vis Unicode 相去甚远。 Matthew Barnett’s regex module for python 2&3 alike 好多了,好多了,最终会取代 re。另见my 3rd OSCON talk。 【参考方案1】:

您正在寻找'(\w/[^/]+/\w*)'

这样使用,

import re
x = re.compile('(\w/[^/]+/\w*)')
s = 'match mysql m/^.\0\0\0\n(4\.[-.\w]+)\0...\0/s p/MySQL/ i/$1/'
y = x.findall(s)
# y = ['m/^.\x00\x00\x00\n(4\\.[-.\\w]+)\x00...\x00/s', 'p/MySQL/', 'i/$1/']

在玩 Edi Weitz 的 Regex Coach 时发现了它,所以感谢 cmets 的问题让我记住了它的存在。

【讨论】:

【参考方案2】:

在 Python 中使用非 ASCII 时要特别小心

Python 如何处理或无法处理模式和字符串中的非 ASCII 存在一些非常微妙的问题。更糟糕的是,这些差异会因您使用的 Python 版本而有很大差异,还取决于您是否拥有“广泛的构建”。

一般来说,当你在处理 Unicode 的东西时,具有广泛构建的 Python 3 效果最好,而具有窄构建的 Python 2 效果最差,但所有组合仍然相距甚远Perl 正则表达式是如何工作的相对于 Unicode。如果您正在寻找 Python 中的 ᴘᴄʀᴇ 模式,您可能需要寻找比其旧的 re 模块更远的地方。

如果您使用足够先进的 Python 版本,那么令人烦恼的“广泛构建”问题终于得到了彻底修复。这是the v3.3 release notes的摘录:

功能

PEP 393 引入的更改如下:

Python 现在始终支持全部范围的 Unicode 代码点,包括非 BMP 代码点(即从 U+0000 到 U+10FFFF)。窄构建和宽构建之间的区别不再存在,Python 现在的行为类似于宽构建,即使在 Windows 下也是如此。 随着窄构建的消亡,窄构建特有的问题也得到了修复,例如: len() 现在对于非 BMP 字符总是返回 1,所以 len('\U0010FFFF') == 1; 代理对不会在字符串文字中重新组合,所以'\uDBFF\uDFFF' != '\U0010FFFF'; 索引或切片非 BMP 字符返回预期值,因此 '\U0010FFFF'[0] 现在返回 '\U0010FFFF' 而不是 '\uDBFF'; 标准库中的所有其他函数现在可以正确处理非 BMP 代码点。 sys.maxunicode 的值现在始终为 1114111(十六进制的 0x10FFFF)。 PyUnicode_GetMax() 函数仍返回 0xFFFF 或 0x10FFFF 以实现向后兼容性,并且它不应与新的 Unicode API 一起使用(请参阅 issue 13054)。 The ./configure 标志 --with-wide-unicode 已被删除。

Python 正则表达式的未来

与标准 Python 发行版的 re 库中当前可用的内容相比,Matthew Barnett’s regex module for both Python 2 and Python 3 alike 在几乎所有可能的方面都要好得多,并且很可能最终会取代 re。它与您的问题特别相关的是,他的 regex 库在各个方面都比 re 现在更 ᴘᴄʀᴇ(ie 它与 Perl 更兼容),这将使您更容易将 Perl 正则表达式移植到 Python。因为它是一个彻底的重写(就像从头开始,而不是像汉堡包:),所以它是在考虑非 ASCII 的情况下编写的,re 不是。

因此,regex 库在处理问题方面更接近于 UTS#18: Unicode Regular Expressions 的(当前)建议。它满足或超过了 UTS#18 1 级要求,在大多数方面(如果不是全部),您通常必须使用 ICU 正则表达式库或 Perl 本身——或者如果您特别勇敢,新的 Java 7 更新其正则表达式,因为这也符合来自 UTS#18 的Level One requirements。

除了满足那些对于基本 Unicode 支持绝对必要的要求之外,Python 的当前re 库不满足这些要求,很棒的regex 库也满足了级别RL2.5 Named Characters (\N...))、RL2.2 Extended Grapheme Clusters (\X) 和来自 revision 14 of UTS#18 的完整属性的新 RL2.7 的两个要求。

Matthew 的 regex 模块还可以进行 Unicode 大小写折叠,以便不区分大小写的匹配在 Unicode 上可靠地工作,re 没有。

以下内容不再正确,因为regex 现在支持完整的 Unicode 大小写折叠,如 Perl 和 Ruby。

一个非常小的区别是,目前,Perl 的不区分大小写模式使用完全面向字符串的大小写折叠,而他的regex 模块仍然使用简单的面向单字符的大小写折叠,但这是他正在研究的东西.这实际上是一个非常难的问题,除了 Perl 之外,甚至只有 Ruby 尝试过。

在完全大小写的情况下,这意味着(例如)"ß" 现在可以正确匹配 "SS""ss""ſſ""ſs"(等等),此时选择了不区分大小写的匹配。 (这在希腊文中无疑比拉丁文更重要。)

另请参阅来自 my third OSCON2011 talk 的幻灯片或文档源代码,标题为 Unicode 支持大战:好的、坏的和(大部分)丑陋的 javascriptphp、Go、Ruby、Python、Java 和 Perl 的 Unicode 支持问题。如果不能使用 Perl 正则表达式或 ICU 正则表达式库(唉,它没有命名捕获!),那么 Matthew 为 Python 编写的 regex 可能是你最好的选择。


Nᴏᴛᴀ Bᴇɴᴇ s.ᴠ.ᴘ。 (= s'il vous plaît, et meme s'il ne vous plaît pas :) 以下未经请求的非商业非广告不是 实际上是由 Python regex 库的作者放在这里的。 :)

regex功能

Python regex 库具有丰富的功能,其中一些在任何其他正则表达式系统中都找不到。无论您碰巧使用它是因为它的ᴘᴄʀᴇ-ness 还是其出色的 Unicode 支持,这些都非常值得一试。

本模块的一些突出特点是:

Variable-width lookbehind,这是一个在正则表达式引擎中非常罕见的功能,当你真正想要它时却没有它非常令人沮丧。这很可能是正则表达式中最常被请求的功能。 向后搜索,因此您不必先自己反转字符串。 作用域ismx-type 选项,因此(?i:foo) 只为 foo 折叠,而不是整体,或 (?-i:foo) 仅在 foo 上关闭它。这就是 Perl 的工作方式(或可以)。 基于编辑距离的模糊匹配(Udi Manber 的 agrepglimpse 也有) 通过\L<list> 插值的隐式最短到最长排序命名列表 仅与单词开头或结尾而不是任一侧的特定匹配的元字符(\m\M) 支持所有 Unicode 行分隔符(Java 可以做到这一点,Perl 也可以做到这一点,尽管对于 \R per RL1.6 有点不情愿。 根据RL1.3 对括号字符类进行完整的操作——联合、交集、差异和对称差异,这比在 Perl 中进行操作要容易得多。 允许重复捕获组,例如(\w+\s+)+,您可以在其中获取第一组的所有单独匹配项,而不仅仅是最后一个匹配项。 (我相信 C# 也可能做到这一点。) 一种比前瞻中偷偷摸摸的捕获组更直接的方法来获得重叠匹配。 所有组的开始和结束位置,用于以后的切片/子字符串操作,很像 Perl 的 @+@- 数组。 分支重置运算符通过(?|...|...|...|) 重置每个分支中的组编号,就像它在 Perl 中的工作方式一样。 可以配置为让您的咖啡在早上等着您。 支持来自RL2.3 的更复杂的字边界。 默认假定 Unicode 字符串,并且完全支持 RL1.2a 以便 \w\b\s 等在 Unicode 上工作。 支持\X 用于字素。 支持\G 连续点断言。 适用于 64 位构建(re 仅具有 32 位索引)。 支持多线程。

好的,炒作就够了。 :)

又一个很好的替代正则表达式引擎

如果您是正则表达式极客,那么值得一看的最后一个替代方案是 Python library bindings,而不是 Russ Cox 的出色 RE2 library。它还原生支持 Unicode,包括简单的基于字符的大小写折叠,与 re 不同的是,它特别提供了 Unicode 通用类别和 Unicode 脚本字符属性,这是您最常需要的更简单类型 Unicode 的两个关键属性加工。

虽然 RE2 错过了一些 Unicode 功能,例如 ICU、Perl 和 Python 中的 \N... 命名字符支持,但它具有极其强大的计算优势,使其成为首选的正则表达式引擎您担心通过 Web 查询等中的正则表达式进行的基于饥饿的拒绝服务攻击。它通过禁止反向引用来管理这一点,这会导致正则表达式不再有规律,并有可能在时间和空间上出现超指数爆炸。

RE2 的库绑定不仅适用于 C/C++ 和 Python,还适用于 Perl,尤其适用于 Go,它很快就会取代那里的标准正则表达式库。

【讨论】:

【参考方案3】:

由于您想运行 PCRE 正则表达式,并且 Python 的 re 模块已经偏离其原始 PCRE 起源,您可能还想查看Arkadiusz Wahlig's Python bindings for PCRE。这样您就可以访问本机 PCRE,而无需在正则表达式之间进行转换。

【讨论】:

以上是关于Python 中的 Perl 兼容正则表达式 (PCRE)的主要内容,如果未能解决你的问题,请参考以下文章

寻找提示以更好地理解 Perl 兼容的正则表达式运算符和语法

请对 POSIX 风格和兼容 Perl 风格两种正则表达式的主要函数进行类比说明

PHP -- Perl风格正则表达式

将 perl 正则表达式中的键和值传递给哈希

是否有 Python 等效于正则表达式的 Perl "/x" 修饰符?

什么是 PCRE 兼容语法? C# PCRE 兼容吗?