从每列的行中提取部分字符串

从每列的行中提取部分字符串

我有一个超过 20.000 行的文本文件,如下所示:

7   128550681   128550681   Intron:1:36:RETAINED-RETAINED;Transcript:NM_001135914.1;Gene:KCP:protein_coding 1   1   0   0
1   17718672    17718672    Intron:9:16:RETAINED-RETAINED;Transcript:NM_207421.4;Gene:PADI6:protein_coding  1   1   0   0
1   17718672    17718672    Intron:9:16:RETAINED-RETAINED;Transcript:NM_207421.4;Gene:PADI6:protein_coding  1   1   0   0
4   86035   86035   Exon:4:5:RETAINED;Transcript:NM_001286052.1;Gene:ZNF595:protein_coding  1   1   0   0
3   12942851    12942851    Intron:14:14:SKIPPED-ALTTENATIVE_3SS;Transcript:NM_001134382.2;Gene:IQSEC1:protein_coding   1   1   0   0

我需要的是第四列只包含 Gene:genename,所以输出如下:

7   128550681   128550681   Gene:KCP    1   1   0   0
1   17718672    17718672    Gene:PADI6  1   1   0   0
1   17718672    17718672    Gene:PADI6  1   1   0   0
4   86035   86035   Gene:ZNF595 1   1   0   0
3   12942851    12942851    Gene:IQSEC1 1   1   0   0

Gene:genename*当尝试按:或分割时,问题并不总是出现在同一位置;

我知道非常基本的 awk/sed,例如如何选择特定列、如何 grep 包含某些模式的行

答案1

我能够使用以下awk命令来完成此操作:

awk '{sub(/^.*;/,"",$4); print}' input

这将删除第 4 列中的所有内容,直到最后一个;,这可能对您不起作用(请参阅 Steeldriver 的评论)。在这种情况下,请更新您的问题并进行澄清。

答案2

awk仅与 POSIX 定义的结构一起使用,

awk 'match($4, /Gene:(.+)\:/){ $4=substr($4, RSTART, RLENGTH-1) }1' file

为了使输出更加整齐地对齐,请将输出通过管道传输到| column -t将制表符分隔的列。如果您不确定 的位置Gene:genename,请更改 来awk查找该行中任意位置的模式,并使用所需的值修改第四列。更改为$4$0整行)应该可以正常工作。

awk 'match($0, /Gene:(.+)\:/){ $4=substr($0, RSTART, RLENGTH-1) }1' file

答案3

perl -pale 's#(?:\H+\h+){3}\K\H+#($F[3] =~ /(?:^|;)(Gene:[^:]+)/)[0]#e' input-file.txt 

° 如果第四个字段中的基因位置不固定,则可以按上述方法操作。

° 我们通过正则表达式将第四个字段归零(?:\H+\h+){3}\K\H+,并立即将其替换为命令替换部分中使用的另一个正则表达式s///e

答案4

珀尔:

perl -F'\h+' -lane '
    for ( $F[3] ) {
        my $a = index(";$_", ";Gene:"     );
        my $b = index(";$_", ":",    $a+6 );
        $_ = substr(";$_", $a+1, $b-$a-1);
    }
    print join "\t", @F;
' input-file.txt

输出:

7   128550681   128550681   Gene:KCP    1   1   0   0
1   17718672    17718672    Gene:PADI6  1   1   0   0
1   17718672    17718672    Gene:PADI6  1   1   0   0
4   86035   86035   Gene:ZNF595 1   1   0   0
3   12942851    12942851    Gene:IQSEC1 1   1   0   0
$   128550681   128550681   Gene:$$$    1   1   0   0

解释:

  • perl选项:
    • -n=> 调用输入的逐行读取。
    • -F=> 将使FS = horizontal whitespace.
    • -a=> 将每一行拆分为字段(基于-F选项设置的 FS 或默认情况下的单个空格)并将它们存储在 array 中@F
    • -l=> 将使RS = ORS = "\n".
    • -e=> 接下来的内容将被视为Perl代码并应用于每一行,即记录。
  • data structures涉及:
    • @F=> 用拆分记录获得的字段填充的数组。从 0 开始索引。$F[3]记录中的第四个字段也是如此。
    • $a;Gene:=> 保存子字符串在第四个字段中的位置。
    • $b=> 保存子字符串在第 4 个字段中的位置:,可以在 的位置之后查找 6 位数字;Gene:。 IOW,它找到了:后的第二个;Gene。注意:我们在搜索字符串中填充一个分号,即 ,$F[3]因为 的位置Gene:可以是任何地方,所以它也可以位于第四个字段的开头。这是为了应对这种可能性。
    • $_$F[3]=> 保存循环内部的本地化版本for。内置substr函数将提取gene:...信息并将其存储回$F[3].
    • 注意:my变量定义之前的限定符将$a,$b它们标记为词法变量,其范围仅限于循环for
    • 注意:循环$_内部for并不引用当前记录/行。它已被重载并本地化,循环持续时间for$F[3]

GNU Sed:

sed -Ee '
    s/\S+/\n&\n/4
    s/\n(.*;)?(Gene:[^:]+):.*\n/\2/
' input-file.txt

解释:

  • 我们用换行符标记第四个字段。
  • 在当前行中放样区域后,我们然后找出所需的数据(在我们的例子中),Gene:然后,as many non colons we meet on the way before we hit the next colon.
  • 该方法不会干扰各个字段之间存在的间距。这可能重要也可能不重要。
  • 注:仅供参考:假设第四个字段中有一个基因。对于多个基因,它不会出错或发出警告,而是默默地选择该记录的第四个字段的最后一个基因。

相关内容