在字符串中查找与负正则表达式匹配的最后一个位置的python方法

2024-10-03 23:25:38 发布

您现在位置:Python中文网/ 问答频道 /正文

在Python中,我试图找到与给定模式匹配的任意字符串的最后一个位置,该模式被指定为负字符集regex模式。例如,由于字符串uiae1iuae200,并且not的模式是一个数字(Python中的regex模式是[^0-9]),因此我需要'8'('200之前的最后一个'e')。在

What is the most pythonic way to achieve this?

由于在Python文档中快速找到方法文档和最适合的方法有点棘手(由于方法文档位于相应页面的中间位置,比如re page中的re.search()),所以我很快发现自己最好的方法就是使用re.search()-但是当前的表单必须是次优的方法信息技术:

import re
string = 'uiae1iuae200' # the string to investigate
len(string) - re.search(r'[^0-9]', string[::-1]).start()

我对此不满意有两个原因: -a)在与[::-1]一起使用之前,我需要反转string,并且 -b)我还需要反转得到的位置(从len(string)中减去它,因为之前已经颠倒了字符串。在

需要有更好的方法来实现这一点,即使结果是re.search()。在

我知道re.search(...).end()超过了.start(),但是{}似乎把结果分成了几组,因此我没有很快找到一种不麻烦的方法将其应用到最后匹配的组。如果不指定组,.start().end()等,似乎总是匹配第一个组,而第一个组没有关于最后一个匹配的位置信息。然而,选择组似乎首先需要将返回值临时保存在变量中(这会阻止简洁的一行程序),因为我需要访问有关选择最后一个组的信息,然后从该组中选择.end()。在

你的Python疗法是什么?比起拥有最优化的运行时,我更看重pythonic。在

更新

该解决方案也应在角落情况下起作用,如123(没有与regex匹配的位置)、空字符串等。它不应崩溃,例如因为选择了空列表的最后一个索引。然而,由于即使是我上面问题中难看的答案也需要不止一行代码来完成,我想一行代码可能不可能做到这一点(仅仅因为在处理之前需要检查re.search()或{}的返回值)。基于这个原因,我将接受Python式的多线解决方案。在


Tags: theto方法字符串文档researchstring
3条回答

这看起来不像python,因为它不是一个单行线,它使用range(len(foo)),但它非常简单,而且可能不会太低效。在

def last_match(pattern, string):
    for i in range(1, len(string) + 1):
        substring = string[-i:]
        if re.match(pattern, substring):
            return len(string) - i

其思想是从最短到最长迭代string的后缀,并检查它是否与pattern匹配。在

因为我们是从末尾检查的,所以我们确定我们遇到的第一个匹配模式的子字符串是最后一个。在

在我看来,你只需要最后一个与给定模式相匹配的位置(在本例中是非数字模式)。
这就像Python一样:

import re

string = 'uiae1iuae200'
pattern = r'[^0-9]'

match = re.match(fr'.*({pattern})', string)
print(match.end(1) - 1 if match else None)

Output:

8

或者与函数完全相同,并且有更多的测试用例:

^{pr2}$

Output:

[^0-9], uiae1iuae200: 8
[^0-9], 123a: 3
[^0-9], 123: None
[^abc], abcabc1abc: 6
[^1], 11eea11: 4

您可以使用re.finditer来提取所有匹配项的起始位置,并从列表中返回最后一个。试试下面的Python代码:

import re
print([m.start(0) for m in re.finditer(r'\D', 'uiae1iuae200')][-1])

印刷品:

^{pr2}$

编辑: 为了使解决方案更加优雅,以便在所有类型的输入中都能正常工作,下面是更新的代码。现在解决方案分为两行,因为必须执行检查如果list为空,那么它将打印-1,否则将打印索引值:

import re

arr = ['', '123', 'uiae1iuae200', 'uiae1iuae200aaaaaaaa']

for s in arr:
    lst = [m.start() for m in re.finditer(r'\D', s)]
    print(s, ' >', lst[-1] if len(lst) > 0 else None)

打印以下内容,如果没有找到这样的索引,则打印None而不是索引:

  > None
123  > None
uiae1iuae200  > 8
uiae1iuae200aaaaaaaa  > 19

编辑2: 正如OP在他的帖子中所说,\d只是我们开始的一个例子,因此我想出了一个解决方案来处理任何通用的regex。但是,如果这个问题真的只能用\d来解决,那么我可以给出一个更好的解决方案,它根本不需要列表理解,而且可以通过使用更好的regex来查找最后一个出现的非数字字符并打印其位置来轻松编写。我们可以使用.*(\D)regex查找最后出现的非数字,并使用以下Python代码轻松打印其索引:

import re

arr = ['', '123', 'uiae1iuae200', 'uiae1iuae200aaaaaaaa']

for s in arr:
    m = re.match(r'.*(\D)', s)
    print(s, ' >', m.start(1) if m else None)

如果找不到任何非数字字符和None的字符串及其相应索引:

  > None
123  > None
uiae1iuae200  > 8
uiae1iuae200aaaaaaaa  > 19

正如您所看到的,这段代码不需要使用任何列表理解,而且更好,因为它只需通过一个regex调用match来查找索引。在

但如果OP确实意味着要使用任何通用regex模式编写它,那么需要使用comprehension编写上面的代码。我甚至可以把它写成一个函数,它可以把正则表达式(比如\d或者甚至是复杂的)作为参数,并动态地生成一个传递的正则表达式的负数并在代码中使用它。如果真的需要,请告诉我。在

相关问题 更多 >