Python中的Perl兼容正则表达式(PCRE)
我需要在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模块可以解析这种字符串吗?
3 个回答
因为你想使用PCRE正则表达式,而Python的re模块已经和最初的PCRE有些不同,所以你可能还想看看Arkadiusz Wahlig为PCRE提供的Python绑定。这样你就可以直接使用原生的PCRE,不用再在不同的正则表达式风格之间转换了。
你在找的是 '(\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 的 正则表达式教练 时发现这个的,感谢那些评论让我想起了它的存在。
在Python中使用非ASCII字符时要特别小心
Python在处理非ASCII字符时,有一些非常微妙的问题。有时候,它处理得不好。而且,这些问题不仅和你使用的Python版本有关,还和你是否使用了“宽构建”有关。
一般来说,当你在处理Unicode时,Python 3的宽构建效果最好,而Python 2的窄构建效果最差。不过,不管怎样,所有的组合都和Perl的正则表达式在处理Unicode时有很大差距。如果你想在Python中使用ᴘᴄʀᴇ模式,可能需要寻找比它的旧re
模块更远的地方。
令人烦恼的“宽构建”问题已经最终解决了——只要你使用的是足够先进的Python版本。以下是来自v3.3版本说明的一段摘录:
功能
根据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一起使用(参见问题13054)。./configure
标志--with-wide-unicode
已被移除。
Python正则表达式的未来
与标准Python发行版中的re
库相比,Matthew Barnett的regex
模块在几乎所有方面都要好得多,并且很可能最终会取代re
。它与你的问题特别相关,因为他的regex
库在各方面都比现在的re
更兼容Perl,这将使你更容易将Perl的正则表达式移植到Python中。由于这是一次从头开始的重写(不是像汉堡那样的重写 :),它在设计时就考虑到了非ASCII字符,而re
并没有。
因此,regex
库在处理事情时更符合UTS#18: Unicode正则表达式的(当前)建议。它在大多数方面都满足或超过了UTS#18的一级要求,而这些通常需要使用ICU正则表达式库或Perl本身,或者如果你特别勇敢,可以使用Java 7对其正则表达式的新更新,因为它也符合UTS#18的一级要求。
除了满足这些一级要求(这些都是基本的Unicode支持所必需的),但Python当前的re
库并不满足,这个强大的regex
库还满足RL2.5命名字符(\N{...}
)、RL2.2扩展字素簇(\X
)以及来自UTS#18第14版的新RL2.7关于完整属性的要求。
Matthew的regex
模块还支持Unicode的大小写折叠,因此在Unicode上进行不区分大小写的匹配时能可靠工作,而re
则不支持。
regex现在支持完整的Unicode大小写折叠,像Perl和Ruby一样。
一个非常小的区别是,目前Perl的不区分大小写的模式使用完整的字符串导向大小写折叠,而他的regex
模块仍然使用简单的单字符导向大小写折叠,但这是他正在研究的内容。这实际上是一个非常困难的问题,除了Perl,只有Ruby尝试过。
在完整的大小写折叠下,这意味着(例如)"ß"
现在正确匹配"SS"
、"ss"
、"ſſ"
、"ſs"
(等等),当选择不区分大小写的匹配时。(这在希腊字母中比在拉丁字母中更重要。)
还可以查看我在OSCON2011的第三次演讲的幻灯片或文档源代码,标题为“Unicode支持大比拼:好的、坏的和(大多数)丑陋的”,讨论JavaScript、PHP、Go、Ruby、Python、Java和Perl中的Unicode支持的普遍问题。如果你不能使用Perl正则表达式或可能的ICU正则表达式库(可惜它没有命名捕获!),那么Matthew的regex
可能是你最好的选择。
Nᴏᴛᴀ Bᴇɴᴇ s.ᴠ.ᴘ. (= s’il vous plaît, et même s’il ne vous plaît pas :) 以下的非商业性广告并不是由Python regex
库的作者放置的。 :)
酷炫的regex
特性
Python的regex
库有丰富的超酷特性,其中一些在其他任何正则表达式系统中都找不到。这使得无论你是因为其ᴘᴄʀᴇ兼容性还是出色的Unicode支持,都非常值得一试。
这个模块的一些突出特性包括:
- 可变宽度的后向查找,这是正则表达式引擎中非常罕见的特性,当你真的需要它时没有它会非常令人沮丧。这可能是正则表达式中请求最多的特性。
- 反向搜索,这样你就不必先自己反转字符串。
- 作用域
ismx
类型选项,例如(?i:foo)
只对foo进行大小写折叠,而不是整体,或者(?-i:foo)
仅在foo上关闭它。这是Perl的工作方式(或可以这样工作)。 - 基于编辑距离的模糊匹配(Udi Manber的
agrep
和glimpse
也有这个功能) - 通过
\L<list>
插值隐式生成从短到长的排序命名列表 - 特定于单词的元字符,仅匹配单词的开始或结束,而不是任一侧(
\m
,\M
) - 支持所有Unicode行分隔符(Java可以做到这一点,Perl也可以,尽管有点勉强,使用
\R
,根据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库绑定到Russ Cox的出色RE2库。它也原生支持Unicode,包括简单的字符级大小写折叠,并且与re
不同,它显著提供了Unicode通用类别和Unicode脚本字符属性,这两个属性是你在处理简单Unicode时最常需要的。
虽然RE2缺少一些Unicode特性,比如在ICU、Perl和Python中找到的\N{...}
命名字符支持,但它在计算上有极大的优势,使其成为在处理正则表达式时,尤其是在网络查询中防止基于饥饿的拒绝服务攻击的首选引擎。它通过禁止回溯引用来实现这一点,回溯引用会使正则表达式不再是常规的,并可能导致时间和空间的超指数爆炸。
RE2的库绑定不仅适用于C/C++和Python,还适用于Perl,尤其是Go,在那里它即将取代标准正则表达式库。