【问题标题】:Searching strings where substring occur at specific positions with negative look-ahead使用负前瞻搜索子字符串出现在特定位置的字符串
【发布时间】:2017-07-07 04:50:34
【问题描述】:

我在尝试创建一个正则表达式时遇到了一个问题,这应该有助于查找包含特定子字符串组合的字符串。

例如我正在搜索子串组合:

ab-ab-cd

1) "xxxabxxxxxxabxxxxcdxxx" -> 应该是匹配的

2) "xxxabxxxxabxxxxabxxxxcdxxxx -> 不匹配

3) "xxxabxxxxxxxxxxcdxxxx -> 不匹配

让它变得更复杂:

4) "xxxabxxxxxabxxxxcdxxxabxxx -> 也应该是匹配的

我的子串组合也可能是这样的:

ab-cd

ab-ab-ab-cd

ab-cd-ab-cd

对于所有这些(以及更多)示例,我正在寻找一种系统的方法来以系统的方式构建相应的正则表达式,以便仅找到字符串作为匹配项,其中子字符串以正确的顺序和正确的频率出现。

对于“ab-ab-cd”子字符串搜索,我得到了类似的结果,但在示例 4) 的情况下它失败了。

p = re.compile("(?:(?!ab).)*ab.*?ab(?!.*ab).*cd",re.IGNORECASE)

在类似 4) 的情况下,这个有效,但也匹配类似 2) 的字符串:

p = re.compile("(?:(?!ab).)*ab(?:(?!ab).)*ab((?!ab|cd)*).*cd", re.IGNORECASE)

你能指出我的错误吗?

非常感谢!

编辑:

对不起,我的问题不够清楚。我试图将我的问题分解为一个更简单的案例,这可能不是一个好主意。 下面是问题的详细解释:

我有(蛋白质)序列列表,并根据序列模式为每个序列分配特定类型。

因此,我创建了一个字典,其中 type-name 作为键,特征模板(按特定顺序排列的序列特征列表)作为值,例如:

type_a -> [A,A,B,C]

type_b -> [A,B,C]

type_c -> [A,B,A,B]

在其他字典中,我对每个功能都有(简单的)正则表达式模式,例如:

A -> [PHT]AG[QP]LI

B -> RS[TP]EV

C -> ...

D -> ...

现在每个模板(type_a、type_b、...)我现在系统地构建连接的正则表达式模式(即为 type_a 构建一个搜索 A、A、B、C 的正则表达式)。 这将导致另一个 dict 类型为键,完整的正则表达式为值。

现在我想遍历序列列表中的每个序列,并将所有完整的正则表达式模板映射到每个序列。在最好的情况下,只有一个完整的正则表达式(类型)应该与序列匹配。

以上面的示例为例,具有以下正则表达式模板:

光盘

ab-cd

ab-ab-cd

ab-ab-ab-cd

ab-cd-ab-cd

ab-ab-cd-ab

"xxxabxxxxxxabxxxxcdxxx"

->这个序列应该匹配模板“ab-ab-cd”的正则表达式,而不是其他任何一个

使用以下正则表达式,我可以完美地查找 ab-ab-cd。

p = re.compile("(?:(?!ab).)*ab.*?ab(?!.*ab).*cd",re.IGNORECASE)

如果我的测试是正确的,它只会匹配上面的序列 1) 而不是 2) 或 3)。

但是,如果我想搜索 ab-ab-cd-ab,则负前瞻将不允许找到最后一个 ab。我发现类似以下代码的内容可以在第二个“ab”部分之后打破负面预测。据我了解,负前瞻应该以“cd”结束,以便最后一个“ab”可以再次匹配。

p = re.compile("(?:(?!ab).)*ab(?:(?!ab).)*ab((?!ab|cd)*).*cd", re.IGNORECASE)

它解决了来自 ab-ab-cd-ab 的最后一个“ab”的问题。 但不知何故,它现在不仅匹配“cd”之前的 2 次“ab”(序列 1)-ab-ab-cd),而且匹配“cd”之前的 3 次(或更多)“ab”(序列2, ab-ab-ab-cd),这是不应该的。

我希望我的问题更清楚。非常感谢所有答案,明天我回来工作时会尝试代码。非常感谢任何进一步的答案,正则表达式代码的解释(我对正则表达式很陌生)以及使用 re.functions(匹配,最终...)的建议。

谢谢

【问题讨论】:

  • ab-ab-cd 组合是否应该匹配ab_cd_ab_cd 之类的字符串?
  • 如果你不说你想使用哪种re方法,你的问题没有意义:re.searchre.matchre.findall...?
  • 试试^(?:(?!ab).)*ab(?:(?!ab).)*ab(?:(?!ab).)*cd.*$。但是这个问题听起来并不那么清楚。
  • 我试图更新我的问题以更清楚。希望这有助于理解我在寻找什么。也将高度赞赏用于解决我的问题的 re.functions 建议。我对正则表达式不是很有经验。
  • Wiktor 的正则表达式似乎解决了我的问题。非常感谢。任何人都可以提供正则表达式的解释(特别是与我的提案相比,它们没有按应有的方式工作)?

标签: python regex negative-lookahead


【解决方案1】:

您可以使用re.findall 并对其进行后处理。实际上,您希望找到 abcd 的所有实例,并查看您的模式 (['ab', 'ab', 'cd']) 是否位于列表的开头。以下:

import re

test1 = "xxxabxxxxxxabxxxxcdxxx"
test2 = "xxxabxxxxabxxxxabxxxxcdxxxx"
test3 = "xxxabxxxxxxxxxxcdxxxx"
test4 = "xxxabxxxxxabxxxxcdxxxabxxx"

for x in (test1, test2, test3, test4):
    matches = re.findall(r'(ab|cd)', x)
    print matches[:3] == ['ab', 'ab', 'cd']

打印

True
False
False
True

根据需要。

【讨论】:

  • 感谢您的建议。 '(ab|cd)'前面的“r”代表什么?
  • @Sefu 这是一个原始字符串文字,请参阅this question
【解决方案2】:

为什么需要消极的展望? 为什么不使用这么简单的东西:

*ab.*ab.*cd

或者如果你需要它从行首找到匹配,你可以使用:

^.*ab.*ab.*cd

编辑: 在您发表评论后,我了解您的需求。试试这个:

^(?:(?!ab).)*ab(?:(?!ab).)*ab(?:(?!ab).)*cd

【讨论】:

  • 这匹配 xxxabxxxxabxxxxabxxxxcdxxxx,即使它不应该匹配。
  • 你能解释一下正则表达式的作用吗?我在第一部分遇到问题,我认为不是以 ab 开头? (?:(?!ab).)*
  • 关于正则表达式的解释:第一部分 (?:(?!ab).)* 查找前面没有ab的任何字符,然后查找ab,重复两次然后再次任何不以 ab 和 cd 开头的字符。见链接:regex101.com/r/UawK16/1
  • @UriY:我尝试添加扩展正则表达式:p = re.compile("^(?:(?!ab).)*ab(?:(?!ab)。 )*ab(?:(?!ab).)*(?:(?!c‌​d).)*cd(?:(?!cd).)*$‌​", re.IGNORECASE。这应该匹配 ab-ab-cd 但不匹配 ab-ab-cd-cd。但是,它确实像字符串一样数学 ab-ab-cd-cd...
猜你喜欢
  • 2021-11-26
  • 2017-03-27
  • 2017-02-25
  • 2017-03-07
  • 2023-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-06-14
相关资源
最近更新 更多