【问题标题】:Regex: how to find 3 or more matches in a row NOT ONLY one by one正则表达式:如何在一行中找到 3 个或更多匹配项不仅仅是一个一个
【发布时间】:2022-01-04 10:56:24
【问题描述】:

我尝试在文件中查找“1/1”或“0/0”出现 3 次或更多次的行。我在 Python 中使用正则表达式。我用https://regex101.com/ 测试我的正则表达式。

这是我的输入文件的一部分:

0   chr1  1152 NaN   G   A   1355.64     NaN   1/1   0/1   0/1  0/1   1/1   0/1   0/1   0/1   0/1   1/1   0/1   0/1
4   chr1  1331 NaN   A   C   4171.07     NaN   0/0   0/1   0/1  0/1   0/0   0/1   0/1   0/1   0/1   0/0   0/1   0/1
5   chr1  1349 NaN   T   C  11194.50     NaN   0/1   0/1   0/1  0/1   1/1   0/1   0/1   0/1   0/1   1/1   0/1   0/1
6   chr1  1401 NaN   T   G  10825.80     NaN   0/1   0/1   0/1  0/1   1/1   0/1   0/1   0/1   0/1   1/1   0/1   0/1
8   chr1  4045 NaN   G   T   1917.92     NaN   1/1   1/1   1/1  1/1   1/1   1/1   0/1   1/1   0/1   1/1   0/1   1/1

我写了一个正则表达式来查找行首:

r"^\d\s{3}(chr\d)?\s{2}\d+\s+\D+\d+\.\d+\s+\w+"

但我对下一部分有疑问。我试过了:

r"^\d\s{3}(chr\d)?\s{2}\d+\s+\D+\d+\.\d+\s+\w+(\s{2,}1/1|\s{2,}0/0)"

但它只找到第一次出现的“1/1”或“0/0”。当我尝试使用时:

r"^\d\s{3}(chr\d)?\s{2}\d+\s+\D+\d+\.\d+\s+\w+((\s{2,}1/1){3,}|(\s{2,}0/0){3,})"

那么只有一个匹配,其中 '1/1' 出现 3 次或更多,但一个接一个:

8   chr1  4045 NaN   G   T   1917.92     NaN   1/1   1/1   1/1  1/1   1/1   1/1   0/1   1/1   0/1   1/1   0/1   1/1

关于如何查找 >= 3 '1/1' 或 '0/0' 的所有行的任何想法? 非常感谢!

【问题讨论】:

标签: python regex


【解决方案1】:

如果要保留第一个捕获组,可以使用第一个模式,然后匹配 3 次 0/0 或 1/1

^\d\s{3}(chr\d)\s{2}\d+\s+\D+\d+\.\d+\s+\w+(?:(?:\s{2,}\d/\d)*?\s{2,}([10])/\2\b){3}

模式的第二部分:

(?:(?:\s{2,}\d/\d)*\s{2,}([10])/\2){3}
  • (?:非捕获组整体重复
    • (?:非捕获
      • \s{2,}\d/\d 匹配 2 个或更多空白字符
    • )*? 关闭组并选择性地重复非贪婪
    • \s{2,} 匹配 2 个或更多空格字符
    • ([10])/\2\b 捕获第 2 组中的 0 或 1,并匹配 /,后跟对第 2 组的反向引用以匹配 0/01/ 的数字,后跟单词边界以防止部分匹配
  • ){3}关闭小组并重复3次

Regex demo

如果您还想匹配该行的其余部分,您可以将.* 附加到模式中。

【讨论】:

  • 很好,我可能对这个问题采取了错误的看法。老实说,OP 正在寻找相同的序列至少 3 次。但这也是有道理的!
  • @emor 它匹配 0/01/1 并且单词边界用于防止匹配 1/19 例如
  • @emor 试试这个^\d\s{3}(chr\d) {2}\d+ +\D+\d+\.\d+ +\w+(?=(?:(?:\s+[01]/[01])*?\s+1/1){3})(?:(?:(?:\s+[01]/[01])*?\s+0/0){3})(?:\s+[01]/[01])*$ regex101.com/r/dkftVI/1
  • @emor 是的,但你想匹配整行,对吗?因此,如果您不添加匹配行的其余部分,那么您会得到这个regex101.com/r/sjrzyM/1
  • @Thefourthbird,好的,我现在看到了 - 它只匹配像 0/01/10/1 这样的字符串。谢谢,你帮我想想:D
【解决方案2】:

也许您可以使用积极的前瞻:

^\d\s{3}(chr\d){2}\d+ +\D+\d+\.\d+\s+\w+(?=.*(([10])/\3)(?:.*\2){2})(?:\s+[10]/[10]){12}$

在线查看demo

添加部分(?=.*(([10])/\3)(?:.*\2){2})(?:\s+[10]/[10]){12}$表示:

  • (?= - 打开一个积极的前瞻;
    • .* - 匹配除换行符以外的 0+ 个(贪婪)字符;
    • (([10])/\3) - 第二个捕获组,用于捕获正斜杠后重复的 1 或 0;
    • (?:.*\2){2} - 打开一个非捕获组,将 0+ 个字符匹配到第二个捕获组中捕获的模式并匹配两次;
    • ) - 关闭正向前瞻;
  • (?:\s+[10]/[10]){12} - 第二个非捕获组,用于匹配 1+ 个空白字符以及 1 和 0 的模式,正斜杠作为分隔符。匹配该组十二次;
  • $ - 终点线锚。

【讨论】:

  • 啊,你匹配允许的数据12次,这也是一个很好的解决方案。也许作为一个建议,您还可以使用断言 regex101.com/r/D72s7J/1 中的数据格式
  • True @Thefourthbird,但它可能会影响可读性 =)。无论哪种方式,我都想从 OP 那里知道匹配相同模式三次的假设是否是正确的开始。
  • @JvdV,感谢您的解决方案。我不确定我是否正确理解您的正则表达式。为什么在(?:.*\2){2} 中有两次匹配?我需要找到所有出现 '1/1' >=3 或 '0/0' >=3 的行。
  • 它会这样做(检查链接),但如果我们发现三个出现@emor,我们可以停止积极的前瞻
【解决方案3】:

这将起作用:

如果 0/0 在任何一行出现超过 3 次:

(.*(?:0\/0\b).*){3}

如果 1/1 在任何一行出现超过 3 次:

(.*(?:1\/1\b).*){3}

如果 0/0 出现 3 次或 1/1 出现 3 次

(.*(?:1\/1\b).*){3}|(.*(?:0\/0\b).*){3}

如果 0/0 1/1 中的任何一个出现 3 次

(.*(?:1\/1\b).*){3}|(.*(?:0\/0\b).*){3}|(.*((?:0\/0\b)|(?:1\/1)).*){3}

0/0:

1/1:

如果 0/0 出现 3 次或 1/1 出现 3 次

如果 0/0 1/1 中的任何一个出现 3 次

【讨论】:

  • 虽然这可能有效,但您没有考虑到 OP 的初始模式,因此这也可能只匹配 1/1/1/1/1/1 您是否注意到模式完成的步骤数?见regex101.com/r/vx9Lhv/1 没有匹配的时候更担心,见regex101.com/r/0lWuDf/1
  • 不,它不会匹配 1/1/1/1/1/1
  • 对.. 这需要 1/1/1/1,但可以使用输入,emor 正在提供
猜你喜欢
  • 2013-12-01
  • 1970-01-01
  • 2017-02-25
  • 1970-01-01
  • 2014-12-15
  • 2017-11-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多