正则表达式python_Python的隐藏正则表达式宝石

2023-05-16

正则表达式python

There are many terrible modules in the Python standard library, but the Python re module is not one of them. While it’s old and has not been updated in many years, it’s one of the best of all dynamic languages I would argue.

Python标准库中有许多可怕的模块,但是Python re模块不是其中之一。 尽管它已经很旧并且多年没有更新,但它是我认为所有动态语言中最好的语言之一。

What I always found interesting about that module is that Python is one of the few dynamic languages which does not have language integrated regular expression support. However while it lacks syntax and interpreter support for it, it makes up for it with one of the better designed core systems from a pure API point of view. At the same time it’s very bizarre. For instance the parser is written in pure Python which has some bizarre consequences if you ever try to trace Python while importing. You will discover that 90% of your time is probably spent in on of re’s support module.

我对该模块始终感到有趣的是,Python是少数几种不集成语言正则表达式支持的动态语言之一。 但是,尽管它缺乏语法和解释器支持,但从纯API的角度来看,它是使用设计更好的核心系统之一来弥补的。 同时,这非常奇怪。 例如,解析器是用纯Python编写的,如果您在导入时尝试跟踪Python,则会产生一些奇怪的后果。 您会发现90%的时间可能花在了re的支持模块上。

古老但久经考验 (Old But Proven)

The regex module in Python is really old by now and one of the constants in the standard library. Ignoring Python 3 it has not really evolved since its inception other than gaining basic unicode support at one point. Till this date it has a broken member enumeration (Have a look at what dir() returns on a regex pattern object).

到目前为止,Python中的regex模块确实很旧,并且是标准库中的常量之一。 自从它诞生以来,无视Python 3并没有真正发展,只是在某一时刻获得了基本的unicode支持。 到此日期为止,它的成员枚举已损坏(请查看dir()在正则表达式模式对象上返回的内容)。

However one of the nice things about it being old is that it does not change between Python versions and is very reliable. Not once did I have to adjust something because the regex module changed. Given how many regular expressions I’m writing in Python this is good news.

但是,它过时的好处之一是它在Python版本之间不会更改,并且非常可靠。 因为正则表达式模块已更改,所以我不必一次调整任何东西。 考虑到我用Python编写了多少个正则表达式,这是个好消息。

One of the interesting quirks about its design is that its parser and compiler is written in Python but the matcher is written in C. This means we can pass the internal structures of the parser into the compiler to bypass the regex parsing entirely if we would feel like it. Not that this is documented. But it still works.

关于它的设计的一个有趣的怪癖之一是它的解析器和编译器是用Python编写的,而匹配器是用C编写的。这意味着,如果我们愿意,我们可以将解析器的内部结构传递到编译器中,从而完全绕过regex解析。喜欢它。 并不是说这已被记录下来。 但它仍然有效。

There are many other things however that are not or badly documented about the regular expression system, so I want to give some examples of why the Regex module in Python is pretty cool.

但是,关于正则表达式系统还有许多其他事情没有或没有被很好地记录下来,因此我想举一些例子说明为什么Python中的Regex模块非常酷。

迭代匹配 (Iterative Matching)

The best feature of the regex system in Python is without a doubt that it’s making a clear distinction between matching and searching. Something that not many other regular expression engines do. In particular when you perform a match you can provide an index to offset the matching but the matching itself will be anchored to that position.

毫无疑问,Python中的regex系统的最佳功能是它在匹配和搜索之间做出了明确的区分。 其他正则表达式引擎没有的功能。 特别是执行匹配时,您可以提供一个索引来抵消匹配,但是匹配本身将锚定到该位置。

In particular this means you can do something like this:

特别是,这意味着您可以执行以下操作:

>>> >>>  pattern pattern = = rere .. compilecompile (( 'bar''bar' )
)
>>> >>>  string string = = 'foobar'
'foobar'
>>> >>>  patternpattern .. matchmatch (( stringstring ) ) is is None
None
True
True
>>> >>>  patternpattern .. matchmatch (( stringstring , , 33 )
)
<_sre.SRE_Match object at 0x103c9a510>
<_sre.SRE_Match object at 0x103c9a510>

This is immensely useful for building lexers because you can continue to use the special ^ symbol to indicate the beginning of a line of entire string. We just need to increase the index to match further. It also means we do not have to slice up the string ourselves which saves a ton of memory allocations and string copying in the process (not that Python is particularly good at that anyways).

这对于构建词法分析器非常有用,因为您可以继续使用特殊的^符号来指示整个字符串的行的开头。 我们只需要增加索引以进一步匹配即可。 这也意味着我们不必自己对字符串进行切片,从而节省了大量的内存分配和字符串复制过程(并不是说Python尤其擅长于此)。

In addition to the matching Python can search which means it will skip ahead until it finds a match:

除了匹配的Python可以搜索之外,这意味着它将向前跳过直到找到匹配的对象:

不匹配也匹配 (Not Matching is also Matching)

A particular common problem is that the absence of a match is expensive to handle in Python. Think of writing a tokenizer for a wiki like language (like markdown for instance). Between the tokens that indicate formatting, there is a lot of text that also needs handling. So when we match some wiki syntax between all the tokens we care about, we have more tokens which need handling. So how do we skip to those?

一个特别常见的问题是,缺少匹配项在Python中处理起来很昂贵。 考虑为诸如语言之类的Wiki(例如markdown)编写标记器。 在指示格式的标记之间,有很多文本也需要处理。 因此,当我们在所有关心的标记之间匹配某种Wiki语法时,就会有更多需要处理的标记。 那么我们如何跳到那些呢?

One method is to compile a bunch of regular expressions into a list and to then try one by one. If none matches we skip a character ahead:

一种方法是将一堆正则表达式编译为一个列表,然后一个一个地尝试。 如果没有匹配项,我们将跳过前面的字符:

rules rules = = [
    [
    (( 'bold''bold' , , rere .. compilecompile (( r'**'r'**' )),
    )),
    (( 'link''link' , , rere .. compilecompile (( r'[[(.*?)]]'r'[[(.*?)]]' )),
)),
]

]

def def tokenizetokenize (( stringstring ):
    ):
    pos pos = = 0
    0
    last_end last_end = = 0
    0
    while while 11 :
        :
        if if pos pos >= >= lenlen (( stringstring ):
            ):
            break
        break
        for for toktok , , rule rule in in rulesrules :
            :
            match match = = rulerule .. matchmatch (( stringstring , , pospos )
            )
            if if match match is is not not NoneNone :
                :
                startstart , , end end = = matchmatch .. spanspan ()
                ()
                if if start start > > last_endlast_end :
                    :
                    yield yield 'text''text' , , stringstring [[ last_endlast_end :: startstart ]
                ]
                yield yield toktok , , matchmatch .. groupgroup ()
                ()
                last_end last_end = = pos pos = = matchmatch .. endend ()
                ()
                break
        break
        elseelse :
            :
            pos pos += += 1
    1
    if if last_end last_end < < lenlen (( stringstring ):
        ):
        yield yield 'text''text' , , stringstring [[ last_endlast_end :]
:]

This is not a particularly beautiful solution, and it’s also not very fast. The more mismatches we have, the slower we get as we only advance one character at the time and that loop is in interpreted Python. We also are quite inflexible at the moment in how we handle this. For each token we only get the matched text, so if groups are involved we would have to extend this code a bit.

这不是一个特别漂亮的解决方案,也不是很快。 我们之间存在的不匹配越多,我们就越慢,因为我们当时只前进一个字符,并且该循环在解释的Python中进行。 目前,我们在如何处理此问题上也非常僵化。 对于每个令牌,我们只获得匹配的文本,因此,如果涉及到组,则必须稍微扩展此代码。

So is there a better method to do this? What if we could indicate to the regular expression engine that we want it to scan for any of a few regular expressions?

那么有没有更好的方法可以做到这一点? 如果我们可以向正则表达式引擎指示我们希望它扫描几个正则表达式中的任何一个怎么办?

This is where it gets interesting. Fundamentally this is what we do when we write a regular expression with sub-patterns: (a|b). This will search for either a or b. So we could build a humongous regular expression out of all the expressions we have, and then match for that. The downside of this is that we will eventually get super confused with all the groups involved.

这就是它变得有趣的地方。 从根本上讲,这是我们编写带有子模式的正则表达式时所做的工作: (a | b) 。 这将搜索ab 。 因此,我们可以从我们拥有的所有表达式中构建一个庞大的正则表达式,然后进行匹配。 不利的一面是,我们最终将对所有涉及的群体感到超级困惑。

进入扫描仪 (Enter The Scanner)

This is where things get interesting. For the last 15 years or so, there has been a completely undocumented feature in the regular expression engine: the scanner. The scanner is a property of the underlying SRE pattern object where the engine keeps matching after it found a match for the next one. There even exists an re.Scanner class (also undocumented) which is built on top of the SRE pattern scanner which gives this a slightly higher level interface.

这就是事情变得有趣的地方。 在过去的15年左右的时间里,正则表达式引擎中有一个完全未记录的功能:扫描器。 扫描程序是基础SRE模式对象的属性,在找到下一个匹配项之后,引擎将保持匹配。 甚至存在一个re.Scanner类(也未记录),该类建立在SRE模式扫描器的顶部,从而为该接口提供了更高层次的接口。

The scanner as it exists in the re module is not very useful unfortunately for making the ‘not matching’ part faster, but looking at its sourcecode reveals how it’s implemented: on top of the SRE primitives.

不幸的是,存在于re模块中的扫描程序对于加快“不匹配”部分的速度不是很有用,但是查看其源代码可以发现其实现方式:位于SRE原语之上。

The way it works is it accepts a list of regular expression and callback tuples. For each match it invokes the callback with the match object and then builds a result list out of it. When we look at how it’s implemented it manually creates SRE pattern and subpattern objects internally. (Basically it builds a larger regular expression without having to parse it). Armed with this knowledge we can extend this:

它的工作方式是接受正则表达式和回调元组的列表。 对于每个匹配项,它将使用match对象调用回调,然后从中构建一个结果列表。 当我们看一下它是如何实现的时,它会在内部手动创建SRE模式和子模式对象。 (基本上,它无需解析即可构建更大的正则表达式)。 有了这些知识,我们可以扩展此范围:

So how do we use this? Like this:

那么我们该如何使用呢? 像这样:

scanner scanner = = ScannerScanner ([
    ([
    (( 'whitespace''whitespace' , , r's+'r's+' ),
    ),
    (( 'plus''plus' , , r'+'r'+' ),
    ),
    (( 'minus''minus' , , r'-'r'-' ),
    ),
    (( 'mult''mult' , , r'*'r'*' ),
    ),
    (( 'div''div' , , r'/'r'/' ),
    ),
    (( 'num''num' , , r'd+'r'd+' ),
    ),
    (( 'paren_open''paren_open' , , r'('r'(' ),
    ),
    (( 'paren_close''paren_close' , , r')'r')' ),
),
])

])

for for tokentoken , , match match in in scannerscanner .. scanscan (( '(1 + 2) * 3''(1 + 2) * 3' ):
    ):
    print print (( tokentoken , , matchmatch .. groupgroup ())
())

In this form it will raise an EOFError in case it cannot lex something, but if you pass skip=True then it skips over unlexable parts which is perfect for building things like wiki syntax lexers.

在这种形式下,如果无法对某些内容进行语法化处理,则会引发EOFError ,但是如果您传递skip = True,则它将跳过不可语法化的部分,这对于构建诸如Wiki语法词法分析器之类的内容非常理想。

Kong扫描 (Scanning with Holes)

When we skip, we can use match.start() and match.end() to figure out which parts we skipped over. So here the first example adjusted to do exactly that:

跳过时,可以使用match.start()match.end()来确定跳过了哪些部分。 因此,这里将第一个示例调整为完全做到这一点:

整理组 (Fixing up Groups)

One annoying thing is that our group indexes are not local to our own regular expression but to the combined one. This means if you have a rule like (a|b) and you want to access that group by index, it will be wrong. This would require a bit of extra engineering with a class that wraps the SRE match object with a custom one that adjusts the indexes and group names. If you are curious about that I made a more complex version of the above solution that implements a proper match wrapper in a github repository together with some samples of what you can do with it.

一件令人讨厌的事情是,我们的组索引不是我们自己的正则表达式局部的,而是联合的局部表达式。 这意味着,如果您有(a | b)这样的规则,并且想按索引访问该组,那将是错误的。 这将需要对类进行一些额外的工程设计,该类将SRE匹配对象与用于调整索引和组名的自定义对象包装在一起。 如果您对此感到好奇,那么我会为上述解决方案制作一个更复杂的版本,该解决方案在github存储库中实现了正确的匹配包装,以及一些您可以使用它的示例。

翻译自: https://www.pybloggers.com/2015/11/pythons-hidden-regular-expression-gems/

正则表达式python

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

正则表达式python_Python的隐藏正则表达式宝石 的相关文章

  • python:查找围绕某个 GPS 位置的圆的 GPS 坐标的优雅方法

    我有一组以十进制表示的 GPS 坐标 并且我正在寻找一种方法来查找每个位置周围半径可变的圆中的坐标 这是一个例子 http green and energy com downloads test circle html我需要什么 这是一个圆
  • 中断 Select 以添加另一个要在 Python 中监视的套接字

    我正在 Windows XP 应用程序中使用 TCP 实现点对点 IPC 我正在使用select and socketPython 2 6 6 中的模块 我有三个 TCP 线程 一个读取线程通常会阻塞select 一个通常等待事件的写入线程
  • 元组有什么用?

    我现在正在学习 Python 课程 我们刚刚介绍了元组作为数据类型之一 我阅读了它的维基百科页面 但是 我无法弄清楚这种数据类型在实践中会有什么用处 我可以提供一些需要一组不可变数字的示例吗 也许是在 Python 中 这与列表有何不同 每
  • Python 中的哈希映射

    我想用Python实现HashMap 我想请求用户输入 根据他的输入 我从 HashMap 中检索一些信息 如果用户输入HashMap的某个键 我想检索相应的值 如何在 Python 中实现此功能 HashMap
  • 如何使用 opencv.omnidir 模块对鱼眼图像进行去扭曲

    我正在尝试使用全向模块 http docs opencv org trunk db dd2 namespacecv 1 1omnidir html用于对鱼眼图像进行扭曲处理Python 我正在尝试适应这一点C 教程 http docs op
  • 需要在python中找到print或printf的源代码[关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 我正在做一些我不能完全谈论的事情 我
  • 跟踪 pypi 依赖项 - 谁在使用我的包

    无论如何 是否可以通过 pip 或 PyPi 来识别哪些项目 在 Pypi 上发布 可能正在使用我的包 也在 PyPi 上发布 我想确定每个包的用户群以及可能尝试积极与他们互动 预先感谢您的任何答案 即使我想做的事情是不可能的 这实际上是不
  • Python zmq SUB 套接字未接收 MQL5 Zmq PUB 套接字

    我正在尝试在 MQL5 中设置一个 PUB 套接字 并在 Python 中设置一个 SUB 套接字来接收消息 我在 MQL5 中有这个 include
  • 如何将张量流模型部署到azure ml工作台

    我在用Azure ML Workbench执行二元分类 到目前为止 一切正常 我有很好的准确性 我想将模型部署为用于推理的 Web 服务 我真的不知道从哪里开始 azure 提供了这个doc https learn microsoft co
  • 如何通过 TLS 1.2 运行 django runserver

    我正在本地 Mac OS X 机器上测试 Stripe 订单 我正在实现这段代码 stripe api key settings STRIPE SECRET order stripe Order create currency usd em
  • import matplotlib.pyplot 给出 AttributeError: 'NoneType' 对象没有属性 'is_interactive'

    我尝试在 Pycharm 控制台中导入 matplotlib pyplt import matplotlib pyplot as plt 然后作为回报我得到 Traceback most recent call last File D Pr
  • 使用特定颜色和抖动在箱形图上绘制数据点

    我有一个plotly graph objects Box图 我显示了箱形 图中的所有点 我需要根据数据的属性为标记着色 如下所示 我还想抖动这些点 下面未显示 Using Box我可以绘制点并抖动它们 但我不认为我可以给它们着色 fig a
  • 如何断言 Unittest 上的可迭代对象不为空?

    向服务提交查询后 我会收到一本字典或一个列表 我想确保它不为空 我使用Python 2 7 我很惊讶没有任何assertEmpty方法为unittest TestCase类实例 现有的替代方案看起来并不正确 self assertTrue
  • 根据列 value_counts 过滤数据框(pandas)

    我是第一次尝试熊猫 我有一个包含两列的数据框 user id and string 每个 user id 可能有多个字符串 因此会多次出现在数据帧中 我想从中导出另一个数据框 一个只有那些user ids列出至少有 2 个或更多string
  • 为什么 Pickle 协议 4 中的 Pickle 文件是协议 3 中的两倍,而速度却没有任何提升?

    我正在测试 Python 3 4 我注意到 pickle 模块有一个新协议 因此 我对 2 个协议进行了基准测试 def test1 pickle3 open pickle3 wb for i in range 1000000 pickle
  • 模拟pytest中的异常终止

    我的多线程应用程序遇到了一个错误 主线程的任何异常终止 例如 未捕获的异常或某些信号 都会导致其他线程之一死锁 并阻止进程干净退出 我解决了这个问题 但我想添加一个测试来防止回归 但是 我不知道如何在 pytest 中模拟异常终止 如果我只
  • Django-tables2 列总计

    我正在尝试使用此总结列中的所有值文档 https github com bradleyayers django tables2 blob master docs pages column headers and footers rst 但页
  • 如何应用一个函数 n 次? [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 假设我有一个函数 它接受一个参数并返回相同类型的结果 def increment x return x 1 如何制作高阶函数repeat可以
  • 在 JavaScript 函数的 Django 模板中转义字符串参数

    我有一个 JavaScript 函数 它返回一组对象 return Func id name 例如 我在传递包含引号的字符串时遇到问题 Dr Seuss ABC BOOk 是无效语法 I tried name safe 但无济于事 有什么解
  • 使用随机放置的 NaN 创建示例 numpy 数组

    出于测试目的 我想创建一个M by Nnumpy 数组与c随机放置的 NaN import numpy as np M 10 N 5 c 15 A np random randn M N A mask np nan 我在创建时遇到问题mas

随机推荐

  • electron制作聊天界面(仿制qq)

    效果图 样式使用scss和flex布局 这也是制作IM系统的最后一个界面了 在制作之前参考了qq和千牛 需要注意的点 qq将滚动条美化了 而且在无操作的情况下是不会显示的 滚动条美化 webkit scrollbar 滚动条整体样式 wid
  • element-ui中的el-table滚动加载事件

    问题描述 xff1a 当表格数据量过多 xff0c 一次请求回来会很卡 xff0c 同时又不想分页的情况下 xff0c 我们想让鼠标滚动到表格底部时再去请求数据 解决思路 xff1a 项目用的是element ui的框架 xff0c 给el
  • OpenWRT配置IPV6

    准备材料 智博通 WG3526 路由器 MT7621A 16M ROM 512M RAM 中国移动光纤入户 Prefix Delegation前缀委托模式 刷机 OpenWRT 18 06 for ZBT WG3526 配置 etc con
  • chrome浏览器去掉打开新标签的常用地址缩略图

    chrome浏览器是我们最常用的浏览器 xff0c 但是打开标签后会显示历史的缩略图 有时别人借用我们的电脑 xff0c 或者开着电脑演示时 xff0c 这些浏览记录就会被展示出来 xff0c 总是感觉怪怪的 谷歌一番 xff0c 发现了关
  • cisco交换机如何查看CPU和内存使用情况,以及如何查看接口数据量

    switch4006 show processes cpu CPU utilization for five seconds 4 0 one minute 4 five minutes 4 PID Runtime ms Invoked uS
  • Remix OS PC硬盘版的安装方法。

    前言 大家好 xff0c 今天由我 xff0c 功能讨论区版主来给大家介绍一下Remix OS PC硬盘版的安装方法 开始之前大家需要明确几点 xff1a 0 你的电脑需要满足如下要求 xff08 仔细看清楚这个列表 xff0c 缺一不可
  • inline-block在360浏览器中的显示问题

    360浏览器不支持inline block效果 xff0c 在样式表中加入 display inline block zoom 1 display inline 就能达到display inline block的效果了 转载于 https
  • 个人团队贡献分+转会人员

    经过我们的商议 xff0c 个人团队贡献分如下分配 xff1a 黄杨 xff1a 33 王安然 xff1a 32 韩佳胤 xff1a 31 刘俊伟 xff1a 28 林璐 xff1a 29 谢伯炎 xff1a 30 谭传奇 xff1a 27
  • 如何在bash shell命令行中非常有效地搜索历史命令?

    How to search history commands very effectively in bash shell command line 如何在bash shell 命令行中非常有效地搜索历史命令 xff1f Just ente
  • GreenPlum 锁表以及解除锁定

    最近遇到truncate表 xff0c 无法清理的情况 xff0c 在master节点查看加锁情况 xff0c 并未加锁 这种情况极有可能是segment节点相关表加了锁 xff0c 所以遇到这种情况除了排查master节点的锁 xff0c
  • 使用 FreeRTOS 时注意事项总结(基础篇教程完结)

    以下转载自安富莱电子 xff1a http forum armfly com forum php FreeRTOS 的初始化流程 推荐的初始化流程如下 xff0c 本教程配套的所有例子都是采用的这种形式 xff0c 当然 xff0c 不限制
  • 使用Python实现Hadoop MapReduce程序

    为什么80 的码农都做不了架构师 xff1f gt gt gt 笔者的机器运行效果如下 xff08 输入数据是find的帮助手册 xff0c 和笔者预期一样 xff0c the是最多的 xff09 xff1a 以下是原帖 在这个实例中 xf
  • 解决vnc连接Linux出现X形

    编辑vnc配置文件 vnc xstartup如下 xff1a bin sh Uncomment the following two lines for normal desktop unset SESSION MANAGER exec et
  • 交换机 BootROM 下的升级配置

    实验十 交换机 BootROM 下的升级配置 一 实验目的 1 了解什么时候采用 BootROM 升级 xff1b 2 了解怎样使用 BootROM升级交换机 二 应用环境 当交换机的系统文件遭到破坏时 xff0c 已经无法进入正常的CLI
  • 如何利用 Visual Studio 自定义项目或工程模板

    在开发项目的时候 xff0c 由其是商业性质的大型项目时 xff0c 往往需要在每个代码文件上都加上一段关于版权 开发人员的信息 xff0c 并且名称空间上都需要带有公司的标志 这个时候 xff0c 是选择在开发的时候手动添加还是自动生成呢
  • vncserver和Ubuntu Xfce4远程桌面环境的配置,解决不显示图形界面

    vncserver和Ubuntu Xfce4远程桌面环境的配置 参考的http blog 163 com thinki cao blog static 83944875201303014531803 ubuntu用vnc连接后不显示图形界面
  • Windows平台下利用Fastcopy来做数据的定期同步

    FastCopy号称是Windows 平台上最快的文件拷贝 删除软件 xff0c 特别是文件超多 超大的情况下 为此我们在数据备份的时候选择FastCopy 但是 FastCopy如果直接来做计划任务的话会有一个问题 xff0c 因为打开的
  • 善用VS中的Code Snippet来提高开发效率

    前言 在谈谈VS中的模板中 xff0c 我介绍了如何创建项目 项模板 xff0c 这种方式可以在创建项目时省却不少重复性的工作 xff0c 从而提高开发效率 在创建好了项目和文件后 xff0c 就得开始具体的编码了 xff0c 这时又有了新
  • [git]merge和rebase的区别

    前言 我从用git就一直用rebase xff0c 但是新的公司需要用merge命令 xff0c 我不是很明白 xff0c 所以查了一些资料 xff0c 总结了下面的内容 xff0c 如果有什么不妥的地方 xff0c 还望指正 xff0c
  • 正则表达式python_Python的隐藏正则表达式宝石

    正则表达式python There are many terrible modules in the Python standard library but the Python re module is not one of them W