Regex语句只匹配字符串的一部分进行比较- Python

68de4m5k  于 2023-02-10  发布在  Python
关注(0)|答案(1)|浏览(151)

我尝试做的是将值从一个文件匹配到另一个文件,但我只需要匹配字符串的第一部分和最后一部分。
我将每个文件读入一个列表,并根据我创建的不同Regex模式来操作这些文件。一切正常,除了这些类型的值:

V-1\ZDS\R\EMBO-20-1:24
V-1\ZDS\R\EMBO-20-6:24

在这个例子中,我只想匹配“V-1\ZDS\R\EMBO-20”,然后比较字符串末尾的“24”值。“20-x:”中的数字x可以变化,只要这个字符串的开头和结尾部分匹配,就不需要进行比较。
这是我正在使用的正则表达式:

re.compile(r"(?:.*V-1\\ZDS\\R\\EMBO-20-\d.*)(:\d*\w.*)")

过滤完列表后,使用以下函数返回两个集合之间的差值:

funcDiff = lambda x, y: list((set(x)- set(y))) + list((set(y)- set(x)))

是否有一种方法可以获取差异列表并过滤掉在

:

如上文所述?
很抱歉,这是一个显而易见的答案,我是Python和Regex的新手!
我得到的输出是整个字符串之间的差异,因此即使字符串的第一部分和最后一部分匹配,如果'EMBO-20-x'后面的数字也不匹配,它也会返回不同的值。

kr98yfug

kr98yfug1#

在讨论您的问题之前,regex101对于这类事情是一个非常有用的工具。
您的问题源于两个问题:
1.)使用.*的方法
2.)贪婪匹配与非贪婪匹配

##########################################################################################################################################################################################################################################################

.*是一个正则表达式,它很少是您真正想要的。
顺便说一句,一个有用的正则表达式是[^c]*[^c]+,这些表达式匹配除c之外的任何字符,第一个表达式匹配0或更多,第二个匹配1或更多。
.*将尽可能多地匹配所有字符。相反,尝试从更具体的起点开始正则表达式模式。两种好的方法是lookbehind表达式和锚点。
另外,您可能误用了regex.matchregex.findmatch只返回从字符串开头开始的匹配项,而find将返回输入字符串中的任何匹配项。这可能是您首先包含.*的原因。以允许.match调用返回字符串中更深处的匹配。

Lookbehind表达式

网上有更完整的解释,但简而言之,正则表达式模式如下:

(?<=test)foo

将匹配文本foo,但前提是test正好在它前面。更明确地说,以下字符串将不匹配该正则表达式:

foo
test-foo
test foo

但以下字符串将匹配:

testfoo

不过,这将只匹配文本foo

锚钉

^$是特殊字符,匹配文本行的开始和结束。如果您知道您的正则表达式模式将完全匹配一行文本,请以^开始,以$结束。
.*开头并以.*结尾的模式可能是问题的根源。虽然您没有提供输入或代码的完整示例,但您可能使用了match而不是find
在regex中,.匹配任何字符,*表示0次或更多次,这意味着对于任何输入,您的模式都将匹配整个字符串。

贪婪与非贪婪限定符

第二个问题与贪婪有关。当正则表达式模式中包含*时,它们可以匹配0个或更多字符。这可能隐藏问题,因为可以跳过整个*表达式。您的正则表达式很可能将多行文本作为一个匹配项进行匹配,并在单个.*中隐藏多个记录。

真实的答案

考虑到所有这些因素,让我们假设您的输入数据如下所示:

V-1\ZDS\R\EMBO-20-1:24
V-1\ZDS\R\EMBO-20-6:24
V-1\ZDS\R\EMBO-20-3:93
V-1\ZDS\R\EMBO-20-6:22309
V-1\ZDS\R\EMBO-20-8:2238
V-1\ZDS\R\EMBO-20-3:28

更好的正则表达式是:

^V-1\\ZDS\\R\\EMBO-20-\d:(\d+)$

要查看这个正则表达式的运行情况,请点击this链接。
我想强调几点不同之处:

  • 表达式以^开头,以$结尾。这将强制正则表达式只匹配一行。即使模式没有这些字符也能工作,但在使用正则表达式时尽可能明确是一个好习惯。
  • 没有无用的非捕获组。您的示例在开始时有一个(?:)组。这表示一个组没有捕获它的匹配。如果您想多次匹配一个子模式,这很有用((?:ab){5}匹配ababababab,但没有捕获任何内容)。然而,在您的示例中,它什么也没做:)
  • 仅捕获编号。这样可以更容易地提取捕获组的值。
  • 不使用*,使用+一次。+的工作原理与*类似,但它匹配1个或多个字符。这通常更正确,因为它可以防止"跳过"整个字符。

相关问题