【问题标题】:extract string with regex is unstable用正则表达式提取字符串不稳定
【发布时间】:2011-10-10 06:32:09
【问题描述】:

早安,

我有以下我们在上一篇文章中建立的 python 正则表达式文件。这是为了提取任何看起来像 'chr' + number + ':' + bignumber ".." + bignumber 的信息(所以看起来像 chr1:100000..120000) 如果将 chr1 切换为 chrX,则正则表达式脚本将不再工作......

这是原始脚本:

    # Opens each file to read/modify
    infile='myfile.txt'
    outfile='outfile.txt'

    #import Regex
    import re

    with open (infile, mode='r', buffering=-1) as in_f, open (outfile, mode='w', buffering=-1) as out_f:
        f = (i for i in in_f if '\t' in i.rstrip())
        for line in f:
            _, k = line.split('\t',1)
            x = re.findall(r'^1..100\t([+-])chr(\d+):(\d+)\.\.(\d+).+$',k)
            if not x:
                continue
            out_f.write(' '.join(x[0]) + '\n')

如果我改变了这一行:

    x = re.findall(r'^1..100\t([+-])chrX(\d+):(\d+)\.\.(\d+).+$',k)

我无法具体提取看起来像 chrX 等的内容... 你也应该知道有些行可能是空的!

请帮忙 :) 谢谢

【问题讨论】:

  • 你说改的那行完全一样
  • 您对123100␉+ 前缀只字未提。会不会是问题?请显示匹配和不匹配的 k(使用print repr(k))的内容。

标签: python regex string file extract


【解决方案1】:

我不完全理解你的问题,但我会尝试根据你的代码给出一些建议。

这是最重要的一行:

x = re.findall(r'^1..100\t([+-])chr(\d+):(\d+)\.\.(\d+).+$',k)

观察:

0) 我什至不知道buffering=-1 在调用open() 时会做什么。我建议您摆脱它,并允许标准行为,即行缓冲。对于这种情况,这就是您想要的,您希望一次处理一行文件。 (默认与指定buffering=1相同。)

1) re.findall() 返回匹配列表。但是,通过在您的模式中使用$,您可以保证您将获得最多一个匹配项,因为每一行只能有一个行尾。所以你可能应该使用re.search()。您甚至可以使用re.match(),因为您有一个^ 来锚定到行首。

2) 我不建议您使用.split() 方法函数来摆脱前导标签。只需将标签折叠到您的正则表达式中。它更简单、更快捷。

3) 您的模式要求每一行都以这样的字符串开头:

1aa100
100100
1xx100
1xy100

这是你想要的吗?每行是否以始终以“100”结尾的数字开头?如果它始终是一个数字,您可能希望在模式中使用 \d 而不是 .

4) 您需要在上面匹配的类似数字的内容之后添加一个制表符。然后你有一个匹配组,它匹配一个“+”或一个“-”并让你收集匹配的值。我很好奇你会用它做什么。

5) 模式 chr\d+ 将匹配 chr0chr1chr11chr111 等。任意数字组合,最小长度为 1 位。我不确定你是否期望它真正匹配大写的“X”(你谈到匹配chrX),但它肯定不会。

6) 您匹配一个数字、两个实际句点和另一个数字。这看起来完全正确,对我来说很好。然后,在第二个数字之后,将.+ 一起使用。这需要在行尾之前添加一个或多个额外字符。我想知道这是否会导致您的问题。也许您应该使用匹配零个或多个额外字符的.*

7) 如果您使用re.match() 而不是re.findall(),则无需使用x[0] 即可进入匹配组。

8) 如果你有一个匹配组m' '.join(m) 不起作用。你得到一个类型错误。您需要改用' '.join(m.groups())

9) 我认为chr 和两个由.. 分隔的数字的模式本身就很好,所以也许你可以放松模式的其余部分,只匹配那些。

10) 我总是喜欢预编译我的正则表达式模式。它更快,然后您可以在编译模式上使用方法函数。比如pat是一个预编译的正则表达式,你可以使用pat.search(line)搜索一行文本。

综合我的建议,这里有一些 Python 代码供你试用:

import re

infile='myfile.txt'
outfile='outfile.txt'

pat = re.compile(r'([+-])chr([^:]+):(\d+)\.\.(\d+)')

with open(infile, mode='r') as in_f, open(outfile, mode='w') as out_f:
    for line in in_f:
        if '\t' not in line.rstrip():
            continue
        m = pat.search(line)
        if not m:
            continue
        out_f.write(' '.join(m.groups()) + '\n')

编辑:由于您似乎确实希望将字符串 chrX 识别为有效,因此我更改了上面的示例代码。它现在使用 [^:] 来匹配除冒号以外的任何内容,而不是 \d 来匹配数字。上面的代码现在应该匹配chr1:chrX: 或其他任何东西。

【讨论】:

  • 非常感谢。现在我看到我原来的帖子中插入了错字。如果我有 chr[number]:[int}]..[int] 可以工作,但是当我需要提取 chr[letter]:[int]..[int] 时,它根本不起作用。它似乎不识别字母,而只识别数字。那是我的观点。非常感谢我明天会尝试你的建议并更新这篇文章。谢谢!
  • 嘿,我需要修改一下这段代码以适应我们的数据。我又遇到了问题.. 我应该发布一个新问题还是介意你从这里检查它?
  • @madkitty,无论哪种方式都可以。如果您发布问题,我以外的其他人可能会为您回答,您可能会更快地得到答案。如果您确实发布了问题,则应包含返回此问题的链接。
猜你喜欢
  • 2016-01-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-05
  • 2014-08-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多