Pythonic方法查找字符串中与负正则表达式匹配的最后一个位置
在Python中,我尝试在任意字符串中查找与给定模式匹配的最后一个位置,该模式被指定为负字符集正则表达式模式。例如,对于字符串Pythonic方法查找字符串中与负正则表达式匹配的最后一个位置,python,regex,string,regex-negation,Python,Regex,String,Regex Negation,在Python中,我尝试在任意字符串中查找与给定模式匹配的最后一个位置,该模式被指定为负字符集正则表达式模式。例如,对于字符串uiae1iuae200,而不是数字的模式(Python中的regex模式是[^0-9]),我需要“8”(在“200”之前的最后一个“e”)作为结果 实现这一目标的最具Python风格的方式是什么 因为要快速找到方法文档和对Python文档中最适合的方法有点棘手(由于方法文档是在相应页面中间的某个地方,如“代码> Re.Sql())/代码>,我快速发现自己的最佳方式是使用
uiae1iuae200
,而不是数字的模式(Python中的regex模式是[^0-9]
),我需要“8”(在“200”之前的最后一个“e”)作为结果
实现这一目标的最具Python风格的方式是什么
因为要快速找到方法文档和对Python文档中最适合的方法有点棘手(由于方法文档是在相应页面中间的某个地方,如“代码> Re.Sql())/代码>,我快速发现自己的最佳方式是使用<代码> Re.Sql()-但当前表单必须是次优的执行方式:
import re
string = 'uiae1iuae200' # the string to investigate
len(string) - re.search(r'[^0-9]', string[::-1]).start()
我对此不满意,原因有二:
-a)在与[:-1]
一起使用之前,我需要反转字符串
,并且
-b)我还需要反转结果位置(从len(string)
中减去它,因为之前已经反转了字符串
需要有更好的方法来实现这一点,甚至可能有re.search()
的结果
我知道re.search(…).end()
超过了.start()
,但是re.search()
似乎将结果分成了几个组,我没有很快找到一种不麻烦的方法将其应用于最后匹配的组。没有指定组,.start()
,.end()
等似乎总是匹配第一个组,而第一个组没有关于最后一个匹配的位置信息。但是,选择该组似乎首先需要将返回值临时保存在变量中(这会阻止整洁的单行线),因为我需要访问有关选择最后一个组的信息,然后从该组中选择.end()
你的pythonic解决方案是什么?比起拥有最优化的运行时,我更看重pythonic
更新
该解决方案也应适用于特殊情况,如
123
(没有与正则表达式匹配的位置),空字符串等。它不应该因为选择空列表的最后一个索引而崩溃。但是,即使是我在问题中的难看答案也需要多行,我想单行可能不可能做到这一点(只是因为需要检查re.search()
或re.finditer()的返回值)处理它之前。
。出于这个原因,我会接受pythonic多行解决方案。这看起来不像pythonic,因为它不是一行,并且使用了范围(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
的后缀,并检查它是否匹配模式
因为我们是从末尾检查的,所以我们可以确定我们遇到的第一个匹配模式的子字符串是最后一个。您可以使用re.finditer
提取所有匹配的开始位置,并从列表中返回最后一个。请尝试以下Python代码:
import re
print([m.start(0) for m in re.finditer(r'\D', 'uiae1iuae200')][-1])
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)
印刷品:
8
编辑:
为了使解决方案更加优雅,以便在所有类型的输入中都能正常工作,以下是更新的代码。现在,解决方案分为两行,因为必须执行检查。如果列表为空,则它将打印-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
只是我们开始使用的一个例子,因此我提出了一个使用任何通用正则表达式的解决方案。但是,如果这个问题真的必须只使用\d
来解决,那么我可以给出一个更好的解决方案,它根本不需要列表理解,并且可以通过使用更好的r来轻松编写egex查找最后一次出现的非数字字符并打印其位置。我们可以使用*(\D)
regex查找最后一次出现的非数字字符,并使用以下Python代码轻松打印其索引:
import re
print([m.start(0) for m in re.finditer(r'\D', 'uiae1iuae200')][-1])
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确实意味着要使用任何通用的正则表达式模式来编写它,那么就需要我上面使用理解的代码。我甚至可以将它作为一个可以使用正则表达式的函数来编写(比如\d
,甚至是一个复杂的函数)作为参数,将动态生成传递的正则表达式的负数,并在代码中使用。如果确实需要,请告诉我。对我来说,您只需要与给定模式匹配的最后一个位置(在本例中不是数字模式)。
这就像它得到的蟒蛇一样:
import re
string = 'uiae1iuae200'
pattern = r'[^0-9]'
match = re.match(fr'.*({pattern})', string)
print(match.end(1) - 1 if match else None)
输出:
8
[^0-9], uiae1iuae200: 8
[^0-9], 123a: 3
[^0-9], 123: None
[^abc], abcabc1abc: 6
[^1], 11eea11: 4
或者与函数完全相同,并且有更多的测试用例:
import re
def last_match(pattern, string):
match = re.match(fr'.*({pattern})', string)
return match.end(1) - 1 if match else None
cases = [(r'[^0-9]', 'uiae1iuae200'), (r'[^0-9]', '123a'), (r'[^0-9]', '123'), (r'[^abc]', 'abcabc1abc'), (r'[^1]', '11eea11')]
for pattern, string in cases:
print(f'{pattern}, {string}: {last_match(pattern, string)}')
输出:
8
[^0-9], uiae1iuae200: 8
[^0-9], 123a: 3
[^0-9], 123: None
[^abc], abcabc1abc: 6
[^1], 11eea11: 4
“不”或与正则表达式匹配的最后一个位置?最后一个e
匹配[^0-9]
模式。与特定模式不匹配的最后一个位置,如数字。对于数字,这将是[^0-9]
。我会更新问题。如果s='uiae1iuae200aaaaaa'
返回数字akae
(8)或最后一个字符akaa
(19)之前的最后一个字符的索引,则使用uiae1iuae200aaaaaa
返回字符串中的最后一个位置,表示19
。“查找字符串中与正则表达式不匹配的最后一个位置的方法”,实际上,您只想查找与给定正则表达式匹配的最后一个位置,在这种情况下,正则表达式恰好是一个负字符集。这不是pyt