如何用逗号替换特定模式后的空格?

How to replace spaces after a certain pattern with commas?

我是编码新手,正在尝试格式化一些生物信息学数据。我试图用逗号删除 GT:GL:GOF:GQ:NR:NV 之后的所有空格,但不删除格式 xx:xx:xx:xx:xx 之外的任何内容(如示例)。我知道我需要使用 sed 和正则表达式选项,但我不太熟悉如何使用它。我以前从未真正使用过 sed 并且在尝试时感到困惑,因此我们将不胜感激。对不起,如果我的格式不好(这是我的第一个 post)。

编辑 2:这次我从文件中获得了实际数据,这可能有助于解决问题。删除了错误的例子。

新示例:我从我的实际文件中提取此数据(这只是两个示例),它被其他数据包围。本质上,该行有一堆数据,后跟 "GT:GL:GOF:GQ:NR:NV ",之后有更多格式如下所示的数据,最后还有一些随机数据。不幸的是,我无法 post 整行数据,因为它太长了,放不下。

输入

0/1:-1,-1,-1:146:28:14,14:4,0 0/1:-1,-1,-1:134:6:2,2:1,0

输出

0/1:-1,-1,-1:146:28:14,14:4,0,0/1:-1,-1,-1:134:6:2,2:1,0

我假设 xx:xx:xxxx:xx:xx:xx 可以有任意数量的部分,因为有些有 3 个,有些有 4 个。

这很难用 sed 可靠地完成,因为它不支持环顾四周,这似乎是本例中可能需要的。

您可以尝试类似的方法:

perl -pe 's/(?<=\d) (?=\d+(:\d+){2,})/,/g' input.txt

如果你对 sed 有信心,你可以试试这个,但它可能会漏掉一些情况:

sed -r 's/(:[0-9]+) ([0-9]+:)/,/g' input.txt

您也可以在没有正则表达式的情况下使用 awk 实现您想要的结果:

awk '{printf "%s", FSFSFSFS","","; for (i=8;i<=NF;i++) printf "%s", FS$i; print ""}' input.txt

基本上,它从字段 1 到 5 使用默认字段分隔符 ("space") 输出,然后从字段 5 到 7 使用逗号分隔符,然后从字段 8 开始再次使用默认分隔符。

使用基本正则表达式,您可以使用字符类反向引用来完成您的任务,例如

$ sed 's/\([0-9][0-9]*:[0-9][0-9]*\)[ ]\([0-9][0-9]*:[0-9][0-9]*\)/,/g' file
1/0 ./. 0/1 GT:GL:GOF:GQ:NR:NV 1:12:314,213:132:13:31,14:31:31 AB GT BB
1/0 ./. 0/1 GT:GL:GOF:GQ:NR:NV 10:13:12,41:41:1:13,13:131:1:1 AB GT RT
1/0 ./. 0/1 GT:GL:GOF:GQ:NR:NV 1:12:314,213:132:13:31,14:31:31 AB GT

基本上说:

  • 查找并捕获任何 [0-9][0-9]* 一位或多位数字,
  • :
  • 分隔
  • 后跟 [0-9][0-9]* 一个或多个数字 -- 作为捕获组 1,
  • 匹配捕获组 1 之后的 space 和捕获组 2(与捕获组 1 相同),
  • 然后用逗号替换捕获组分隔符 space 使用反向引用 1 和 2(例如 </code> 和 <code>)重新插入捕获组文本,最后
  • 进行替换全局(例如g)以替换所有匹配项。

根据发布的新输入进行编辑

如果您仍然需要添加所有原始逗号, 您现在想要在 ,0 0/ 之间添加一个逗号(逗号在单个 -数字后跟 space 替换为逗号,后跟一个数字和一个正斜杠),那么您需要做的就是使您的捕获组有条件(如上所示捕获原始数据) - 或 - 捕获这个新段。您可以通过在条件之间包含一个 OR(例如 \| 在基本正则表达式术语中)来做到这一点。

例如,在第一个捕获组的末尾添加 \|,[0-9],在第二个捕获组的末尾添加 \|[0-9][/],例如

$ sed 's/\([0-9][0-9]*:[0-9][0-9]*\|,[0-9]\)[ ]\([0-9][0-9]*:[0-9][0-9]*\|[0-9][/]\)/,/g' file
0/1:-1,-1,-1:146:28:14,14:4,0,0/1:-1,-1,-1:134:6:2,2:1,0

如果您的文件中有其他注意事项,我建议您 post 几行完整的输入,如果它们太长,则创建一个 zip、gzip、bzip 或 xz 文件并 post 将其添加到 pastebin 之类的网站,然后将 link 添加到您的问题中。

如果你现在真正关心的是,0 0/中的space,那么你可以将sed命令缩短为:

$ sed 's/\(,[0-9]\)[[:space:]]\([0-9][/]\)/,/g' file
0/1:-1,-1,-1:146:28:14,14:4,0,0/1:-1,-1,-1:134:6:2,2:1,0

(注意: 我已经包含了 [[:space:]] 来处理任何白色 space (space,制表符,...)在新示例中只是文字 [ ] (space) 让我知道这是否解决了问题。

能否请您尝试以下。这将负责打印那些与正则表达式不匹配的值。此外,我们还可以通过 [0-9]+\.{4} 等方式使 match 中提到的正则表达式更短一些,因为这是在旧 awk 上测试的,所以无法测试它。

awk '
BEGIN{
  OFS=","
}
match([=10=],/GT:GL:GOF:GQ:NR:NV [0-9]+:[0-9]+:[0-9]+:[0-9]+:[0-9]+/){
  value=substr([=10=],RSTART!=1?1:RSTART,RSTART+RLENGTH-1)
  value1=substr([=10=],RSTART+RLENGTH+1)
  gsub(/[[:space:]]+/,",",value1)
  print value,value1
  next
}
1
'  Input_file

perl myscript.pl '0/1:-1,-1,-1:146:28:14,14:4,0 0/1:-1,-1,-1:134:6:2,2:1,0'

myscript.pl,

  #!/usr/local/ActivePerl-5.20/bin/env perl
    my $input = $ARGV[0];
    $input =~ s/ /\,/g; 
    print $input, "\n";
__DATA__

输出

0/1:-1,-1,-1:146:28:14,14:4,0,0/1:-1,-1,-1:134:6:2,2 :1,0

这将删除所有 space,而不仅仅是有问题的 space