对于下面的文件,我想提取" XC:Z:"之后的两个字符串。和" XM:Z:"。例如:
该文件的原始版本比以下示例具有更多列和数百万行,但它应该为您提供这样的想法:
MOUSE_10 XC:Z:TGGTCGGCGCGT RG:Z:A XM:Z:GAGTCCGT ZP:i:33
MOUSE_10 XC:Z:GAAGCCGCTTCC NM:i:0 XM:Z:ACCGACGG AS:i:16
MOUSE_10 ZP:i:36 XC:Z:TCCCCGGGTACA NM:i:0 XM:Z:GGGACGGG ZP:i:28
MOUSE_10 XC:Z:CAAATTTGGAAA RG:Z:A NM:i:1 XM:Z:GCAGATAG
此外,以下每个标准都是奖励,但如果您能够将其付诸实施则不是强制性的:
来自awk extract multiple groups from each line的答案非常接近它,但每当我尝试使用匹配(...)时,我会在意外令牌附近出现"语法错误"消息。
期待您的解决方案!
谢谢,
菲利克斯
答案 0 :(得分:1)
使用sed,您可以在XC:Z:
和XM:Z
之后捕获非空格字符:
sed -n 's/.*XC:Z:\([^[:blank:]]*\).*XM:Z:\([^[:blank:]]*\).*/\1, \2/p;' file
您可以为反转值添加第二个s
命令:
sed -n 's/.*XC:Z:\([^[:blank:]]*\).*XM:Z:\([^[:blank:]]*\).*/\1, \2/;s/.*XM:Z:\([^[:blank:]]*\).*XC:Z:\([^[:blank:]]*\).*/\1, \2/;p;' file
答案 1 :(得分:0)
遵循awk
解决方案可能对您有帮助。
awk '
/XC:Z:/{
match($0,/XC:[^ ]*/);
num=split(substr($0,RSTART,RLENGTH),a,":");
match($0,/XM:[^ ]*/);
num1=split(substr($0,RSTART,RLENGTH),b,":");
print a[num],b[num1]
}' Input_file
输出如下。
TGGTCGGCGCGT GAGTCCGT
GAAGCCGCTTCC ACCGACGG
TCCCCGGGTACA GGGACGGG
CAAATTTGGAAA GCAGATAG
答案 2 :(得分:0)
另一个awk
$ awk '{c=p=""; # need to reset c and p before each line
for(i=1;i<=NF;i++) # for all fields in the line
if($i~/^XC:Z:/) c=substr($i,6) # check pattern from the start of field
else if($i~/^XM:Z:/) p=substr($i,6) # if didn't match check other other pattern
if(c && p) print c,p}' file # if both matched print
TGGTCGGCGCGT GAGTCCGT
GAAGCCGCTTCC ACCGACGG
TCCCCGGGTACA GGGACGGG
CAAATTTGGAAA GCAGATAG
如果同一行上有多个实例,则会打印最后一个匹配项。这是另一个略有不同的特征。
$ awk 'function s(x) {return ($i~x)?substr($i,6):""}
{c=p="";
for(i=1;i<=NF;i++) {
c=c?c:s("^XC:Z:"); p=p?p:s("^XM:Z:");
if(c && p)
{print c,p; next}}}' file
TGGTCGGCGCGT GAGTCCGT
GAAGCCGCTTCC ACCGACGG
TCCCCGGGTACA GGGACGGG
CAAATTTGGAAA GCAGATAG
这将在另一个匹配的第一个匹配之前打印重复匹配的最后一个。它们成对出现,将打印第一对。
答案 3 :(得分:0)
如果我们不知道XC和XM出现的顺序 你可以尝试这个sed
sed -E 'h;s/(XC:Z:.*XM:Z:)//;tA;x;s/(.*XM:Z:)([^[:blank:]]*)(.*XC:Z:)([^[:blank:]]*)(.*)/\4,\2/;b;:A;x;s/(.*XC:Z:)([^[:blank:]]*)(.*XM:Z:)([^[:blank:]]*)(.*)/\2,\4/' infile
解释:
sed -E '
h
# keep the line in the hold space
s/(XC:Z:.*XM:Z:)//;x;tA
# if XCZ come before XMZ, go to A but before everything restore the pattern space with x
s/(.*XM:Z:)([^[:blank:]]*)(.*XC:Z:)([^[:blank:]]*)(.*)/\4,\2/
# XMZ come before XCZ, get the interresting parts and reorder it
b
# It is all for this line
:A
s/(.*XC:Z:)([^[:blank:]]*)(.*XM:Z:)([^[:blank:]]*)(.*)/\2,\4/
# XCZ come before XMZ, get the interresting parts
' infile
答案 4 :(得分:0)
使用POSIX awk
,您只能使用IEEE Std 1003.1-2008定义的字符串函数match(s,ere)
:
match(s, ere)
返回位置,以字符为单位,编号为1,in 扩展正则表达式发生的字符串,如果是,则为零 它根本不会发生。 RSTART应设置为起始位置 (与返回值相同),如果未找到匹配则为零; RLENGTH应设置为匹配字符串的长度,如果不是则设置为-1 找到匹配。
您要匹配的模式是XM:Z:[^[:blank:]]*
和XC:Z:[^[:blank:]]*
。但是,假设您没有任何包含PXM:Z:
之类的字符串(即提前搜索到的字符串的额外非空白字符)。当在$0
行中找到模式时,您只需要提取重要部分,这些部分将在5个字符后开始。
以下代码执行上述操作:
awk '{match($0,/XM:Z:[^[:blank:]]*/);xm=substr($0,RSTART+5,RLENGTH-5)}
{match($0,/XC:Z:[^[:blank:]]*/);xc=substr($0,RSTART+5,RLENGTH-5)}
{print xc","xm}' <file>
如您所见,第一行提取XM
,第二行XC
,第三行用逗号分隔符","
打印结果。
备注 - 此处做出以下假设:
xm
和xc
字符串[^[:blank:]]X[CM]:Z:[^[:blank:]]*
类型的字符串如果您愿意使用gawk
,那么您可以使用patsplit
函数进行字符串操作(Ref。here)。您可以使用单个正则表达式/X[CM]:Z:[^[:blank:]]*/
执行此操作。这样可以在一次调用中直接为您提供所请求的字符串,其中包括XM:Z:
或XM:C:
部分。之后,您可以轻松地对它们进行排序并提取最后的部分。
以下几行在gawk
gawk '{patsplit($0,a,/X[MC]:Z:[^[:blank:]]*/) }
{xc=(a[1]~/^XC/)?a[1]:a[2]; xm=(a[1]~/^XC/)?a[2]:a[1]}
{print substr(xc,5)","substr(xm,5)' <file>
尽管如此,我认为awk
解决方案从对称的角度来看更清晰。