使用正则表达式进行类型验证
Using regex for type validation
我说要学习正则表达式,我正在尝试使用它来解决问题。
我需要编写一个获取 VCF 文件的函数,并且需要检查文件中的某些列,看看它们是否符合要求。
第一列应以“chr”开头,以 1-99 之间的任意数字或字母“M,X,Y”中的一个结尾。
第二列必须是大于 0 的所有 int 数字。
第 4 和第 5 列需要是下一个字母“ATCG”之一(只有一个)。
如果其中一个陈述即使在一行中也是错误的,它应该 return 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
我检查了两个文件 - 一个应该 return 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
输出应该是 true 还是 false 取决于条件。
感谢任何帮助!
您需要一一解决的问题:
- 第一列应以
chr
开头,以 1-99
之间的任意数字或字母 M,X,Y
- chr(?:0?[1-9]|[1-9][0-9]|[MXY])
- 第二列必须是大于
0
的所有整数 - 0*[1-9][0-9]*
- 第4和第5列需要是下一个字母“ATCG”之一(只有一个) -
[ATCG]
.
现在,考虑到列分隔符是您在代码示例中使用的分隔符(制表符,\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
这样,删除 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 列):零个或多个 0
,一个非零数字,然后是任何零个或多个数字
\t
- 一个标签
[^\t]*
(第 3 列)- 制表符以外的任何零个或多个字符
(?:\t[ATCG]){2}
(第 4 列和第 5 列)- 选项卡,来自 ATCG
集的字母,两次
\t
- 一个标签。
我说要学习正则表达式,我正在尝试使用它来解决问题。 我需要编写一个获取 VCF 文件的函数,并且需要检查文件中的某些列,看看它们是否符合要求。
第一列应以“chr”开头,以 1-99 之间的任意数字或字母“M,X,Y”中的一个结尾。 第二列必须是大于 0 的所有 int 数字。 第 4 和第 5 列需要是下一个字母“ATCG”之一(只有一个)。 如果其中一个陈述即使在一行中也是错误的,它应该 return 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
我检查了两个文件 - 一个应该 return 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
输出应该是 true 还是 false 取决于条件。
感谢任何帮助!
您需要一一解决的问题:
- 第一列应以
chr
开头,以1-99
之间的任意数字或字母M,X,Y
-chr(?:0?[1-9]|[1-9][0-9]|[MXY])
- 第二列必须是大于
0
的所有整数 -0*[1-9][0-9]*
- 第4和第5列需要是下一个字母“ATCG”之一(只有一个) -
[ATCG]
.
现在,考虑到列分隔符是您在代码示例中使用的分隔符(制表符,\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
这样,删除 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 列):零个或多个0
,一个非零数字,然后是任何零个或多个数字\t
- 一个标签[^\t]*
(第 3 列)- 制表符以外的任何零个或多个字符(?:\t[ATCG]){2}
(第 4 列和第 5 列)- 选项卡,来自ATCG
集的字母,两次\t
- 一个标签。