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 支持大战:好的、坏的和(大部分)丑陋的” javascript、php、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 的 agrep
和 glimpse
也有)
通过\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 风格两种正则表达式的主要函数进行类比说明