替换每行中前三个字符的出现

时间:2018-06-18 07:31:07

标签: sed replace bioinformatics text-processing

我有一个制表符分隔的遗传变体文件,其中INFO列有许多以分号分隔的标记:

Chr Start   End Ref Alt ExAC_ALL    ExAC_AFR    ExAC_AMR    ExAC_EAS    ExAC_FIN    ExAC_NFE    ExAC_OTH    ExAC_SAS    Otherinfo   QUAL    DP  Chr Start       Ref Alt QUAL    FILTER  INFO
1   15847952    15847952    G   C   .   .   .   .   .   .   .   .   .   241.9   76196   1   15847952    .   G   C   241.9   PASS    AC=2;AF=0;AN=18332;BaseQRankSum=0.731;ClippingRankSum=-0.731;DP=76196;ExcessHet=3.1;FS=0;InbreedingCoeff=-0.0456;MLEAC=2;MLEAF=0;MQ=38.93;MQRankSum=0.515;NEGATIVE_TRAIN_SITE;QD=10.52;ReadPosRankSum=0.89;SOR=0.481;VQSLOD=-1.406        culprit=MQ
1   15847963    15847963    A   C   .   .   .   .   .   .   .   .   .   1607.1  126156  1   15847963    .   A   C   1607.1  PASS    AC=2;AF=0;AN=22004;BaseQRankSum=0.851;ClippingRankSum=-0.419;DP=126156;ExcessHet=3.4904;FS=0;InbreedingCoeff=0.0299;MLEAC=2;MLEAF=0;MQ=59.29;MQRankSum=0.18;QD=1.55;ReadPosRankSum=0.067;SOR=0.651;VQSLOD=0.995        culprit=QD
1   15847964    15847966    GCC -   .   .   .   .   .   .   .   .   .   1607.1  126156  1   15847963    .   AGCC    A   1607.1  PASS    AC=63;AF=0.003;AN=22004;BaseQRankSum=0.851;ClippingRankSum=-0.419;DP=126156;ExcessHet=3.4904;FS=0;InbreedingCoeff=0.0299;MLEAC=55;MLEAF=0.002;MQ=59.29;MQRankSum=0.18;QD=1.55;ReadPosRankSum=0.067;SOR=0.651;VQSLOD=0.995        culprit=QD
1   15847978    15847978    C   T   .   .   .   .   .   .   .   .   .   648.41  234344  1   15847978    .   C   T   648.41  PASS    AC=9;AF=0;AN=25894;BaseQRankSum=-0.572;ClippingRankSum=-0.404;DP=234344;ExcessHet=3.348;FS=2.639;InbreedingCoeff=-0.0098;MLEAC=6;MLEAF=0;MQ=58.71;MQRankSum=-0.456;NEGATIVE_TRAIN_SITE;QD=4.13;ReadPosRankSum=-0.456;SOR=0.452;VQSLOD=-1.238        culprit=QD

我想在INFO列中拆分前3个以分号分隔的术语:

AC=2;AF=0;AN=18332

这样他们就变成了:

AC=2    AF=0    AN=18332    BaseQRankSum=0.731;ClippingRankSum=-0.731;DP=76196;ExcessHet=3.1;FS=0;InbreedingCoeff=-0.0456;MLEAC=2;MLEAF=0;MQ=38.93;MQRankSum=0.515;NEGATIVE_TRAIN_SITE;QD=10.52;ReadPosRankSum=0.89;SOR=0.481;VQSLOD=-1.406        culprit=M

到目前为止,我已尝试使用sed的以下表达式:

sed -i .bk 's/\(A.=.*\);/\1        /g' allChr_ExAC38.hg38_multianno.txt

但这不会产生任何变化。

理想情况下,我一直在寻找一种方法来告诉sed替换;的分号tab的前3个出现,但's/;/ /g3'似乎没有意思是。

6 个答案:

答案 0 :(得分:4)

使用Perl代替sed:

perl -i.bk -pe '$c = 0; s/;/\t/ while $c++ < 3' -- file.txt

答案 1 :(得分:0)

请您试着跟随并告诉我这是否对您有帮助。

awk '
FNR==1{
  print;
  next}
{
  num=split($(NF-1),array,";");
  for(i=4;i<=num;i++){
    val=val?val ";"array[i]:array[i]};
    $(NF-1)=array[1] OFS array[2] OFS array[3] OFS val;
    val="";
    $1=$1
}
1
' OFS="\t"  Input_file

答案 2 :(得分:0)

你的正则表达式中的.*是贪婪的,并且会在行上尽可能多地匹配文本,直到最后一个分号之前(但不会超出,因为那样整个正则表达式根本就不匹配)。

你不能混合/3/g;后者意味着,在每一行上替换所有次出现,因此它与/3直接相矛盾,sed表示在一行上最多只替换三次出现。

但是,“没有变化”似乎是错误的;如果你的正则表达式完全匹配,匹配行上的最后一个分号将被替换。

某些正则表达式引擎支持非贪婪匹配,但.不是其中之一。只要有一个分隔符字符就可以用来限制贪婪,无论如何使用它是一个更好的解决方案。在您的情况下,只需将[^;]替换为sed 's/\(A.=[^;]*\);/\1 /3' allChr_ExAC38.hg38_multianno.txt 即可说出“除(换行符号)分号以外的任何字符”而不是“任何字符(换行符除外)。”

-i .bk

(这将打印到标准输出进行验证;一旦看到结果正确,就将.放回去。)

根据您的示例数据,或许可以考虑将表达式中的剩余[A-Z]替换为[^;],将[^;=]替换为[0-9]甚至public long SaveUsers(Users users) { long id = -1; ContentValues contentValues = null; try { contentValues = new ContentValues(); contentValues.put("name", users.getName()); contentValues.put("email", users.getEmail()); contentValues.put("phone", users.getPhone()); contentValues.put("password", users.getPassword()); db=sqliteHelper.getWritableDatabase(); id = db.insert(SqliteHelper.TABLE_USERS, null, contentValues); } catch (Exception e) { Log.d("Database Insert","Exception:"+e.getMessage()); } finally { if(db!=null && db.isOpen()) db.close(); } return id; } 。你的正则表达式越具体越好。

答案 3 :(得分:0)

你可以试试这个awk

awk '{for(i=1;i<4;i++)sub(";","\t")}1' infile

答案 4 :(得分:0)

这可能适合你(GNU sed):

sed -i.bak 's/;/\n/3;h;y/;/\t/;G;s/\n.*\n/\t/' file

用换行符替换第三个;,制作该行的副本,将所有;替换为\t,然后附上副本,使用\t将第一行的末尾替换为第二行的中间。

根据定义,一行由换行符划分,除非由程序员引入,否则行不能包含换行符。

答案 5 :(得分:0)

如果出现次数合理,您可以多次使用管道发送 sed,即

sed -E -e 's/[0-9]{4}/****/'| sed -E -e 's/[0-9]{4}/****/'| sed -E -e 's/[0-9]{4}/****/'

将像这样屏蔽前 3 组 4 位数的信用卡号

Input:
1234 5678 9101 1234  

Output:
**** **** **** 1234