我有一個檔案(約 50,000 行)text.txt 如下,其中包含來自五個人(AB、BB、CA、DD、GG)的一些基因資訊。檔案中的 \t 是制表符分隔符。檔案中還有很多沒用的資訊,我想清理一下。所以我需要的是提取帶有'transcript=' id 的物種名稱,如果他們有的話,還提取'DD:'和'GG:'部分。
$頭文本.txt
GeneA\tAB:xrbyk | jdnif | otherText\tBB:abdf | jdhfkc | otherDifferentText\tCA:bdmf | nfjvks | transcript=aaabb.1\tDD:hudnf.1 type=cds\tGG:jdubf.1 type=cds
GeneB\tBB:dfsfg | dfsfvdf | otherDifferent\tCA:zdcfsdf | xfgdfgs | transcript=sdfs.1\tDD:sdfsw.1 type=cds\tGG:fghfg.1 type=cds
GeneC\tAB:dsfsdf | xdvv | otherText1\tBB:xdsd | sdfsdf | otherDifferentText2\tDD:hudnf.1 type=cds\tGG:jdubf.1 type=cds
GeneD\tAB:dfsdf | Asda | transcript=asdasd.2\tCA:bdmf | nfjvks | transcript=aaabb.1\tDD:hudnf.1 type=cds\tGG:jdubf.1 type=cds
我希望輸出是
GeneA\tCA:transcript=aaabb.1\tDD:hudnf.1\tGG:jdubf.1
GeneB\tCA:transcript=sdfs.1\tDD:sdfsw.1\tGG:fghfg.1
GeneC\tDD:hudnf.1\tGG:jdubf.1
GeneD\tAB:transcript=asdasd.2\tCA:transcript=aaabb.1\tDD:hudnf.1\tGG:jdubf.1
找了一個下午想了想,只有第一列基因名稱按物種拆開這個檔案,然后分別修改每個檔案,最后根據基因名稱合并檔案的想法。但是正如您所看到的,檔案的每一行不必具有相同數量的欄位,因此我不能簡單地用于awk列印某一列。我不確定如何按物種將它們撕裂。
我試圖模仿這個的使用如何使用 sed/grep 提取兩個單詞之間的文本?,但沒有成功。我還閱讀了一些關于 Python 如何拆分文本的資訊(因為我開始學習這種語言),但仍然無法弄清楚。有人可以幫忙嗎?非常感謝!
更新輸入資料的澄清:在上面的例子中,每個個體的基因資訊由制表符(\t)分隔,這意味著個體名稱加冒號(例如AB:)之后的所有文本都屬于個體(例如 AB 的“xrbyk | jdnif | otherText”)。最終輸出中是否保留個人取決于是否有該個人的“transcript=”資訊,除了DD和GG。這就是為什么在最終輸出中第一行以 CA 開頭但不以 AB 開頭的原因。
uj5u.com熱心網友回復:
這個解決方案有點長,但應該很容易使用:
#!/usr/bin/env python3
# main.py
import csv
import fileinput
import re
def filter_fields(row):
output = []
for field_number, field in enumerate(row, 1):
if field_number == 1:
output.append(field)
elif "DD:" in field or "GG:" in field:
output.append(field.split()[0])
elif "transcript=" in field:
# Remove stuff from after the colon to the last space
output.append(re.sub(r":.* ", ":", field))
return "\t".join(output)
reader = csv.reader(fileinput.input(), delimiter="\t")
for row in reader:
print(filter_fields(row))
如何運行它:
# Output to the screen
python3 main.py text.txt
# Output to a file
python3 main.py text.txt > out.txt
# Use as a filter
cat text.txt | python3 main.py
筆記
- 在這個解決方案中,每一行文本都被分成一行欄位。
- 該功能
filter_fields將獲取每一行,決定要保留和重新格式化的欄位。然后它回傳這些欄位,制表符分隔。 re.sub(...)電話說:洗掉冒號后的所有內容,直到最后一個空格。
uj5u.com熱心網友回復:
該任務很簡單,可以通過定義正則運算式指定感興趣的資訊在一行代碼中解決。
測驗輸入資料,將檔案名替換while <DATA>為while <>腳本的引數。
use strict;
use warnings;
use feature 'say';
my $re = qr/(Gene.|[A-Z]{2}:(?=[^:]*transcript=)|transcript=\S |GG:\S |DD:\S )/;
say join("\t",/$re/g) while <DATA>;
exit 0;
__DATA__
GeneA AB:xrbyk | jdnif | otherText BB:abdf | jdhfkc | otherDifferentText CA:bdmf | nfjvks | transcript=aaabb.1 DD:hudnf.1 type=cds GG:jdubf.1 type=cds
GeneB BB:dfsfg | dfsfvdf | otherDifferent CA:zdcfsdf | xfgdfgs | transcript=sdfs.1 DD:sdfsw.1 type=cds GG:fghfg.1 type=cds
GeneC AB:dsfsdf | xdvv | otherText1 BB:xdsd | sdfsdf | otherDifferentText2 DD:hudnf.1 type=cds GG:jdubf.1 type=cds
GeneD AB:dfsdf | Asda | transcript=asdasd.2 CA:bdmf | nfjvks | transcript=aaabb.1 DD:hudnf.1 type=cds GG:jdubf.1 type=cds
輸出
GeneA CA: transcript=aaabb.1 DD:hudnf.1 GG:jdubf.1
GeneB CA: transcript=sdfs.1 DD:sdfsw.1 GG:fghfg.1
GeneC DD:hudnf.1 GG:jdubf.1
GeneD AB: transcript=asdasd.2 CA: transcript=aaabb.1 DD:hudnf.1 GG:jdubf.1
只需少量更改代碼,即可獲得所需的確切輸出
use strict;
use warnings;
use feature 'say';
my $re = qr/(Gene.|[A-Z]{2}:transcript=\S |GG:\S |DD:\S )/;
while( <DATA> ) {
s/[^:]*(?=transcript=)//g;
say join("\t",/$re/g);
}
exit 0;
__DATA__
GeneA AB:xrbyk | jdnif | otherText BB:abdf | jdhfkc | otherDifferentText CA:bdmf | nfjvks | transcript=aaabb.1 DD:hudnf.1 type=cds GG:jdubf.1 type=cds
GeneB BB:dfsfg | dfsfvdf | otherDifferent CA:zdcfsdf | xfgdfgs | transcript=sdfs.1 DD:sdfsw.1 type=cds GG:fghfg.1 type=cds
GeneC AB:dsfsdf | xdvv | otherText1 BB:xdsd | sdfsdf | otherDifferentText2 DD:hudnf.1 type=cds GG:jdubf.1 type=cds
GeneD AB:dfsdf | Asda | transcript=asdasd.2 CA:bdmf | nfjvks | transcript=aaabb.1 DD:hudnf.1 type=cds GG:jdubf.1 type=cds
輸出
GeneA CA:transcript=aaabb.1 DD:hudnf.1 GG:jdubf.1
GeneB CA:transcript=sdfs.1 DD:sdfsw.1 GG:fghfg.1
GeneC DD:hudnf.1 GG:jdubf.1
GeneD AB:transcript=asdasd.2 CA:transcript=aaabb.1 DD:hudnf.1 GG:jdubf.1
uj5u.com熱心網友回復:
假設\t您的示例文本中的那些是真正的選項卡,那么這個 Perl 單行就可以做到。如果它們是文字\t文本,則需要稍微調整一下。將您想要獲取的每個欄位放在GG:.
perl -lne '@wanted = $_ =~ m{(^Gene[ABCD]|(?:transcript=|DD:|GG:)\S )}g; print join "\t", @wanted if @wanted; ' inputfile.txt > outputfile.txt
輸出:
GeneA transcript=aaabb.1 DD:hudnf.1 GG:jdubf.1
GeneB transcript=sdfs.1 DD:sdfsw.1 GG:fghfg.1
GeneC DD:hudnf.1 GG:jdubf.1
GeneD transcript=asdasd.2 transcript=aaabb.1 DD:hudnf.1 GG:jdubf.1
關于您的說明,這一班輪將使您可以很好地控制捕獲的內容。這更像是一種完整的決議方法。
perl -lne '($gene, @parts) = split/\t/,$_; my @wanted; foreach $p (@parts) { $p =~ m{(?|^([A-Z]{2}:).*?(transcript=\S )|(DD:\S )|(GG:\S ))} and push @wanted, "$1$2"; }; print join "\t", $gene, @wanted if @wanted; ' inputfile.txt > outputfile.txt
輸出:
GeneA CA:transcript=aaabb.1 DD:hudnf.1 GG:jdubf.1
GeneB CA:transcript=sdfs.1 DD:sdfsw.1 GG:fghfg.1
GeneC DD:hudnf.1 GG:jdubf.1
GeneD AB:transcript=asdasd.2 CA:transcript=aaabb.1 DD:hudnf.1 GG:jdubf.1
這將獲取所有 DD 和 GG 第一個組件以及其中包含 atranscript=的任何 ID。
它是這樣作業的。
- 拆分基因并分解每個標簽分隔的部分
- 在每個部分中使用正則運算式獲取我們關心的位
@wanted保存匹配的位并僅在正則運算式匹配時將其推入- 正則
(?|運算式項導致編號的捕獲變數在交替時保持不變,而不是繼續上升。即我們只有$1and$2而不是$1, $2, $3, $4. - 如果有任何東西,列印出該行
@wanted
請記住,每次對任務進行“簡化”時,您都可能會丟失您真正想要的資料。如果資料足夠復雜,您最終可能會得到一個完整的決議器。
單擊此處閱讀有關如何使用 Perl 進行流水線操作的更多資訊。https://perldoc.perl.org/perlrun
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/512212.html
上一篇:使用制表符分隔符決議文本檔案
