【问题标题】:Using regex for type validation使用正则表达式进行类型验证
【发布时间】:2021-08-11 12:25:27
【问题描述】:

我说要学习正则表达式,我正在尝试使用它来解决问题。 我需要编写一个获取 VCF 文件的函数,并且需要检查文件中的某些列,看看它们是否符合要求。

第一列应以“chr”开头,以 1-99 之间的任意数字或字母“M,X,Y”之一结尾。 第二列必须是所有大于 0 的整数。 第 4 列和第 5 列需要是下一个字母“ATCG”之一(仅其中一个)。 如果其中一个语句即使在一行中也是错误的,它也应该返回 false。

这是我写的代码:

def isVCF(file):
    with open(file, "r+") as my_file:
        lines = my_file.readlines()
        for line in lines:
            columns = line.split("\t")
        num_format = re.compile("^[+]?[1-9][0-9]*\.?[0-9]+$")
        if (re.match(r"^chr(?:[1-9][0-9]?|[XYM])$", columns[0]) 
            and re.match(num_format, columns[1])
            and re.match(r"^[ATGC]$", columns[3]) 
            and re.match(r"^[ATGC]$", columns[4])): 
            return True
        else:
            return False

我检查了两个文件 - 一个应该返回 True,另一个应该返回 False,但我对它们都得到 True,所以我尝试逐行进行测试,但仍然得到 True。 文件示例:

ChrX, 74226650, ., T, C, 50, ., DP=385;VDB=0;SGB=-0.693147;RPB=0.982669;MQB=1;BQB=0.947576;MQ0F=0;AC=2;AN=2;DP4=0,95,0,289;MQ=20, GT:PL:DP, 1/1:78,127,0:384

输出应该是或真或假取决于条件。

感谢任何帮助!

【问题讨论】:

  • 为什么是正则表达式?对于第一列,这可能是一个不错的选择,但对于其他列,使用columns[1].isdecimal() 和columns[3] in {'A', 'T', 'G', 'C'} 会更容易。
  • 我是新手,我知道我可以使用其他更简单的方法来解决它,但我想练习正则表达式
  • 您能否提供一个示例 VCF 文件以及它的确切预期输出?谢谢
  • @ggorlen 我找不到上传文件的位置,但我添加了它的图像
  • 谢谢,但不可能从图像中真正分辨出字符级别发生了什么,例如,是制表符还是空格(多少个空格?)分隔、隐藏字符、看起来像的 unicode 字符像 ASCII 字符等,所以它需要做出可能导致错误答案的假设/猜测——对您或其他任何人都没有帮助。我无法由此判断文本行之间是否有两个换行符或只有一个。请问可以发text吗?谢谢。

标签: python regex function boolean


【解决方案1】:

你需要一一解决问题:

  • 第一列应该以chr 开头并以1-99 之间的任意数字或M,X,Y 中的一个字母结尾 - chr(?:0?[1-9]|[1-9][0-9]|[MXY])
  • 第二列必须是大于 0 的所有 int 数字 - 0*[1-9][0-9]*
  • 第 4 列和第 5 列必须是下一个字母“ATCG”之一(仅其中一个) - [ATCG]。

现在,考虑到列分隔符是您在代码示例中使用的分隔符(TAB 字符,\t),您可以使用

def isVCF(file):
    num_format = re.compile(r"^chr(?:0?[1-9]|[1-9][0-9]|[MXY])\t0*[1-9][0-9]*\t[^\t]*(?:\t[ATCG]){2}\t", re.I)
    with open(file, "r+") as my_file:
        for line in my_file:
            if not num_format.match(line):
                return False
        return False

请参阅regex demo。

注意,我使用re.I 来启用不区分大小写,因为您在问题中同时使用了chr 和Chr,如果您只需要以这种方式匹配Chr 和chr,请删除re.I 和将chr 替换为(?i:chr)。

详情:

  • ^ - 字符串开头
  • chr(第 1 列的开头) - chr 字符串
  • (?:0?[1-9]|[1-9][0-9]|[MXY])(第 1 列末尾):可选的 0,然后是一个非零数字,或从 1 到 9 的数字,然后是任意一位数字(0 - 99),或一封来自MXY的信
  • \t - 一个标签
  • 0*[1-9][0-9]*(第 2 列):零个或多个 0s,一个非零数字,然后是任何零个或多个数字
  • \t - 一个标签
  • [^\t]*(第 3 列)- 除制表符之外的任何零个或多个字符
  • (?:\t[ATCG]){2}(第 4 列和第 5 列)- 制表符,来自 ATCG 的字母集,两次
  • \t - 一个标签。

【讨论】:

  • 谢谢!你的意思是第一个返回是假的,另一个是真的吗?顺便说一句,如果我需要将第 4 列和第 5 列设为“ATCG”(仅限大写),我是否要写 - ['[ATCG]+]]?
  • @ranbar 我解释了这个模式,它完全按照你写的那样做。
  • 可以,谢谢!
猜你喜欢
  • 2020-02-18
  • 2014-12-25
  • 2014-04-21
  • 2020-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多