如何使用同一行中的部分字符串来替换字符串?

如何使用同一行中的部分字符串来替换字符串?

我在 Linux 机器上有一个如下所示的文件,但它gene_id是错误的。所以我想将"PB"中的字符串替换为同一行中的gene_idtranscript_id

$ cat try.gff

transcript  30351   32332   .   +   .   gene_id "PB"; transcript_id "PB.1.66";
exon    30351   31677   .   +   .   gene_id "PB"; transcript_id "PB.1.59";
exon    31758   31871   .   +   .   gene_id "PB"; transcript_id "PB.1.40";
exon    31968   32178   .   +   .   gene_id "PB"; transcript_id "PB.1.30";
exon    32257   32332   .   +   .   gene_id "PB"; transcript_id "PB.1.20";
transcript  30351   32332   .   +   .   gene_id "PB"; transcript_id "PB.28.309";
exon    30351   31677   .   +   .   gene_id "PB"; transcript_id "PB.58.900";
exon    31758   31871   .   +   .   gene_id "PB"; transcript_id "PB.10000.1001";
exon    31968   32178   .   +   .   gene_id "PB"; transcript_id "PB.19897.1087541";
exon    32257   32332   .   +   .   gene_id "PB"; transcript_id "PB.1.11";

预期结果

transcript  30351   32332   .   +   .   gene_id "PB.1"; transcript_id "PB.1.66";
exon    30351   31677   .   +   .   gene_id "PB.1"; transcript_id "PB.1.59";
exon    31758   31871   .   +   .   gene_id "PB.1"; transcript_id "PB.1.40";
exon    31968   32178   .   +   .   gene_id "PB.1"; transcript_id "PB.1.30";
exon    32257   32332   .   +   .   gene_id "PB.1"; transcript_id "PB.1.20";
transcript  30351   32332   .   +   .   gene_id "PB.28"; transcript_id "PB.28.309";
exon    30351   31677   .   +   .   gene_id "PB.58"; transcript_id "PB.58.900";
exon    31758   31871   .   +   .   gene_id "PB.10000"; transcript_id "PB.10000.1001";
exon    31968   32178   .   +   .   gene_id "PB.19897"; transcript_id "PB.19897.1087541";
exon    32257   32332   .   +   .   gene_id "PB.1"; transcript_id "PB.1.11";

我设法获得了正确的文本以替换为代码awk -F";" '{gsub(" transcript_id ","");print $2}' try.gff | sed 's/"//g' | cut -d '.' -f 1,2

PB.1
PB.1
PB.1
PB.1
PB.1
PB.28
PB.58
PB.10000
PB.19897
PB.1

我怎样才能更换零件"PB"中的零件gene_id

答案1

sed在每个 Unix 机器上的任何 shell 中使用 any :

$ sed 's/\(.*gene_id "\)[^"]*\(.*"\([^.]*\.[^.]*\).*\)/\1\3\2/' try.gff
transcript  30351   32332   .   +   .   gene_id "PB.1"; transcript_id "PB.1.66";
exon    30351   31677   .   +   .   gene_id "PB.1"; transcript_id "PB.1.59";
exon    31758   31871   .   +   .   gene_id "PB.1"; transcript_id "PB.1.40";
exon    31968   32178   .   +   .   gene_id "PB.1"; transcript_id "PB.1.30";
exon    32257   32332   .   +   .   gene_id "PB.1"; transcript_id "PB.1.20";
transcript  30351   32332   .   +   .   gene_id "PB.28"; transcript_id "PB.28.309";
exon    30351   31677   .   +   .   gene_id "PB.58"; transcript_id "PB.58.900";
exon    31758   31871   .   +   .   gene_id "PB.10000"; transcript_id "PB.10000.1001";
exon    31968   32178   .   +   .   gene_id "PB.19897"; transcript_id "PB.19897.1087541";
exon    32257   32332   .   +   .   gene_id "PB.1"; transcript_id "PB.1.11";

在正则表达式部分中,每个\(都会启动一个捕获组,该捕获组由匹配的\).在替换部分中,every\<digit>指的是与捕获组中的正则表达式段匹配的字符串。 so\1指的是匹配的字符串\(.*gene_id "\)等等。其余的只是基本的正则表达式段(例如,.*表示任何字符的 0 次或多次重复,[^"]*表示除 之外的任何字符的零次或多次重复",以及\.表示文字.)。

答案2

使用sed

$ sed 's/"[A-Z]\+\("[^"]*\(.*\)\..*\)/\2\1/' input_file
transcript  30351   32332   .   +   .   gene_id "PB.1"; transcript_id "PB.1.66";
exon    30351   31677   .   +   .   gene_id "PB.1"; transcript_id "PB.1.59";
exon    31758   31871   .   +   .   gene_id "PB.1"; transcript_id "PB.1.40";
exon    31968   32178   .   +   .   gene_id "PB.1"; transcript_id "PB.1.30";
exon    32257   32332   .   +   .   gene_id "PB.1"; transcript_id "PB.1.20";
transcript  30351   32332   .   +   .   gene_id "PB.28"; transcript_id "PB.28.309";
exon    30351   31677   .   +   .   gene_id "PB.58"; transcript_id "PB.58.900";
exon    31758   31871   .   +   .   gene_id "PB.10000"; transcript_id "PB.10000.1001";
exon    31968   32178   .   +   .   gene_id "PB.19897"; transcript_id "PB.19897.1087541";
exon    32257   32332   .   +   .   gene_id "PB.1"; transcript_id "PB.1.11";

答案3

使用(以前称为 Perl_6)

简单的方法(假设 TSV 文件gff格式):

raku -e 'my @a = lines>>.split("\t").flat; @a[7,17,27...*] = @a[9,19,29...*];    \
         @a[7,17,27...*].=comb(/ <alpha>+ \. <digit>+ /).=map(q["] ~ * ~ q["]);  \
         .put for @a.rotor(10)>>.join("\t");'  

上面的代码只是将每个选项卡和十个元素拆分line\t一个flat完全线性的数组(10 行 x 10 列 = 100 个元素)。每个第 8 列gene_id(零索引 = 7)都会被第 10 列transcript_id(零索引 = 9)覆盖。只要您给它足够的提示,Raku 就会计算出索引序列的其余部分。

transcript_id复制完整内容后,就可以很简单地comb取出<alpha>+ \. \d+所需的字符,q["] ~ * ~ q["]将它们用引号引起来,然后rotor每 10 个元素即可重建 10 x 10 表。


纯粹的正则表达式方式(更难):

~$ raku -pe 's/ <?after ^ .+? gene_id \s \" > (.+?)  (\"\; \s transcript_id \s \")  (<alpha>+ \. \d+) <?before \.> /$2$1$2/;' try.gff

或者

~$ raku -pe 's/  <?after ^ .+? gene_id \s \c[QUOTATION MARK] > (.+?)  (\c[QUOTATION MARK] \; \s transcript_id \s \")  (<alpha>+ \. \d+) <?before \.> /$2$1$2/;' try.gff

这里使用 Raku 的-pe自动打印逐行标志,与熟悉的s///替换运算符结合使用。搜索五个正则表达式原子,并用括号捕获三个原子:

  1. 零宽度正向后查找,<?after … >目标^是字符串开头gene_id \s \"(包括尾随空格和引号),
  2. [捕获为$0]非贪婪的.+?任意字符一次或多次,即要被丢弃的gene_id本身,
  3. [捕获为] 包含该行部分的$1文本(包括周围的空格和标点符号),transcript_id
  4. [捕获为]的$2所需部分,然后<alpha>+ \. \d+transcript_id
  5. 零宽度正前瞻<?before … >,在第二个点之前停止前面的捕获\.

最后在替换中,$2用captured来替换$0capture。和$1捕获$2将恢复到正常位置。

输入示例:

transcript  30351   32332   .   +   .   gene_id "PB"; transcript_id "PB.1.66";
exon    30351   31677   .   +   .   gene_id "PB"; transcript_id "PB.1.59";
exon    31758   31871   .   +   .   gene_id "PB"; transcript_id "PB.1.40";
exon    31968   32178   .   +   .   gene_id "PB"; transcript_id "PB.1.30";
exon    32257   32332   .   +   .   gene_id "PB"; transcript_id "PB.1.20";
transcript  30351   32332   .   +   .   gene_id "PB"; transcript_id "PB.28.309";
exon    30351   31677   .   +   .   gene_id "PB"; transcript_id "PB.58.900";
exon    31758   31871   .   +   .   gene_id "PB"; transcript_id "PB.10000.1001";
exon    31968   32178   .   +   .   gene_id "PB"; transcript_id "PB.19897.1087541";
exon    32257   32332   .   +   .   gene_id "PB"; transcript_id "PB.1.11";

示例输出:

transcript  30351   32332   .   +   .   gene_id "PB.1"; transcript_id "PB.1.66";
exon    30351   31677   .   +   .   gene_id "PB.1"; transcript_id "PB.1.59";
exon    31758   31871   .   +   .   gene_id "PB.1"; transcript_id "PB.1.40";
exon    31968   32178   .   +   .   gene_id "PB.1"; transcript_id "PB.1.30";
exon    32257   32332   .   +   .   gene_id "PB.1"; transcript_id "PB.1.20";
transcript  30351   32332   .   +   .   gene_id "PB.28"; transcript_id "PB.28.309";
exon    30351   31677   .   +   .   gene_id "PB.58"; transcript_id "PB.58.900";
exon    31758   31871   .   +   .   gene_id "PB.10000"; transcript_id "PB.10000.1001";
exon    31968   32178   .   +   .   gene_id "PB.19897"; transcript_id "PB.19897.1087541";
exon    32257   32332   .   +   .   gene_id "PB.1"; transcript_id "PB.1.11";

https://docs.raku.org/language/regexes
https://raku.org

相关内容