한 줄에 gene_id와 유전자 이름이 포함된 파일이 있습니다. 이후의 단어를 바꾸고 싶습니다.유전자 ID이후라는 단어로유전자아니면 그 이후제품아니면 그 이후새싹(일부 누락된 경우)
다음은 줄의 예입니다.
chrM Gnomon CDS 8345 8513 . + 1 gene_id "cds-XP_008824843.3"; transcript_id "cds-XP_008824843.3"; Parent "rna-XM_008826621.3"; Dbxref "GeneID:103728653_Genbank:XP_008824843.3"; Name "XP_008824843.3"; end_range "8513,."; gbkey "CDS"; gene "semaphorin-3F"; partial "true"; product "semaphorin-3F"; protein_id "XP_008824843.3"; sprot "sp|Q13275|SEM3F_HUMAN";
chrM StringTie exon 2754 3700 . + . gene_id "cds-YP_007626758.1"; transcript_id "cds-YP_007626758.1"; Parent "gene-ND1"; Dbxref "Genbank:YP_007626758.1,Gene "ID:15088436"; Name "YP_007626758.1"; Note "TAAstopcodoniscompletedbytheadditionof3'AresiduestothemRNA"; gbkey "CDS"; gene "ND1"; product "NADHdehydrogenasesubunit1"; protein_id "YP_007626758.1"; transl_except "(pos:3700..3700%2Caa:TERM)"; transl_table "2";
나는 sed로 그것을 만들려고 노력했습니다 :
sed -E 's/[^gene_id] .*?;/[^gene] .*?;|[^sprot] .*?;|[^product] .*?;/g'
그러나 결과는 올바르지 않았습니다.
chrM Gnomon CDS 8345 8513 . + 1 gene_id "cds-XP_008824843.3"[^gene] .*?;|[^sprot] .*?;|[^product] .*?;
chrM StringTie exon 2754 3700 . + . gene_id "cds-YP_007626758.1"[^gene] .*?;|[^sprot] .*?;|[^product] .*?;
하지만 모든 줄을 저장하고 싶지만 그 뒤에 다른 단어로유전자 ID, 이와 같이:
chrM Gnomon CDS 8345 8513 . + 1 gene_id "semaphorin-3F"; transcript_id "cds-XP_008824843.3"; Parent "rna-XM_008826621.3"; Dbxref "GeneID:103728653_Genbank:XP_008824843.3"; Name "XP_008824843.3"; end_range "8513,."; gbkey "CDS"; gene "semaphorin-3F"; partial "true"; product "semaphorin-3F"; protein_id "XP_008824843.3"; sprot "sp|Q13275|SEM3F_HUMAN";
chrM StringTie exon 2754 3700 . + . gene_id "ND1"; transcript_id "cds-YP_007626758.1"; Parent "gene-ND1"; Dbxref "Genbank:YP_007626758.1,Gene "ID:15088436"; Name "YP_007626758.1"; Note "TAAstopcodoniscompletedbytheadditionof3'AresiduestothemRNA"; gbkey "CDS"; gene "ND1"; product "NADHdehydrogenasesubunit1"; protein_id "YP_007626758.1"; transl_except "(pos:3700..3700%2Caa:TERM)"; transl_table "2";
또는 다음과 같습니다(다른 사람이 놓친 경우).
chrM Gnomon CDS 8345 8513 . + 1 gene_id "sp|Q13275|SEM3F_HUMAN"; transcript_id "cds-XP_008824843.3"; Parent "rna-XM_008826621.3"; Dbxref "GeneID:103728653_Genbank:XP_008824843.3"; Name "XP_008824843.3"; end_range "8513,."; gbkey "CDS"; gene "semaphorin-3F"; partial "true"; product "semaphorin-3F"; protein_id "XP_008824843.3"; sprot "sp|Q13275|SEM3F_HUMAN";
chrM StringTie exon 2754 3700 . + . gene_id "ND1"; transcript_id "cds-YP_007626758.1"; Parent "gene-ND1"; Dbxref "Genbank:YP_007626758.1,Gene "ID:15088436"; Name "YP_007626758.1"; Note "TAAstopcodoniscompletedbytheadditionof3'AresiduestothemRNA"; gbkey "CDS"; gene "ND1"; product "NADHdehydrogenasesubunit1"; protein_id "YP_007626758.1"; transl_except "(pos:3700..3700%2Caa:TERM)"; transl_table "2";
어떤 도움이라도 대단히 감사하겠습니다.
답변1
다음 perl 스크립트는 각 입력 행에서 gene
, product
및 를 sprot
해당 순서대로 일치시키려고 시도합니다(즉, 제품보다 유전자를 우선순위로 두고 sprot보다 제품을 우선순위로 둡니다). 그 중 하나가 일치하면 일치 후의 단어를 추출합니다. 단어는 큰따옴표로 묶인 것으로 간주됩니다.
gene_id
일치하는 항목이 발견되면 이후의 단어를 추출된 단어로 바꿉니다 .
수정 여부에 관계없이 행이 인쇄됩니다.
#!/usr/bin/perl
while (<>) {
my $word = '';
if (m/\b(?:gene)\s+("[^"]*")/) {
$word = $1;
} elsif (m/\b(?:product)\s+("[^"]*")/) {
$word = $1;
} elsif (m/\b(?:sprot)\s+("[^"]*")/) {
$word = $1;
};
if ($word) {
s/\bgene_id\s+(?:"[^"]*")/gene_id $word/
};
print;
}
또는 루프를 사용하여 일치 키워드를 반복하도록 작성할 수도 있습니다.
#!/usr/bin/perl
while (<>) {
my $word = '';
foreach my $match (qw(gene product sprot)) {
if (m/\b(?:$match)\s+("[^"]*")/) {
$word = $1;
last; # first match wins, exit this loop
}
};
if ($word) {
s/\bgene_id\s+(?:"[^"]*")/gene_id $word/
};
print;
}
IMO, 이 버전은 읽고 이해하기가 더 쉽기 때문에 더 좋습니다(특히 루프는 foreach
단어 목록을 반복하는 것에 대해 강조합니다). 더 중요한 것은 $word = $1
명령문 반복을 방지한다는 것입니다. 명령문을 변경하거나 추가 코드를 추가해야 하는 경우, 세 번이 아닌 한 번만 수행하면 되는 경우 오류가 발생할 가능성이 줄어듭니다. "반복하지 마세요"는 이와 같은 사소한 작은 프로그램에서는 그다지 중요하지 않지만 대규모 프로그램에서는 매우 중요할 수 있습니다. 어쨌든 반복을 피하거나 최소화하는 것은 좋은 프로그래밍 습관입니다.
일치 순서가 중요하지 않은 경우(예: 하나만 발견되었더라도 상관하지 않는 경우) 스크립트를 단순화할 수 있습니다.
#!/usr/bin/perl
while (<>) {
my ($word) = m/\b(?:gene|product|sprot)\s+("[^"]*")/;
if ($word) {
s/\bgene_id\s+(?:"[^"]*")/gene_id $word/
};
print;
}
사용하는 스크립트의 버전에 관계없이 이를 로 저장 replace.pl
하고 로 실행 가능하게 만드십시오 chmod +x replace.pl
. 아니면 모두 replace1.pl
, replace2.pl
, 로 시도해 보세요 replace3.pl
. 그런 다음 다음과 같이 실행하십시오.
$ ./replace.pl input.txt
chrM Gnomon CDS 8345 8513 . + 1 gene_id "semaphorin-3F"; transcript_id "cds-XP_008824843.3"; Parent "rna-XM_008826621.3"; Dbxref "GeneID:103728653_Genbank:XP_008824843.3"; Name "XP_008824843.3"; end_range "8513,."; gbkey "CDS"; gene "semaphorin-3F"; partial "true"; product "semaphorin-3F"; protein_id "XP_008824843.3"; sprot "sp|Q13275|SEM3F_HUMAN";
chrM StringTie exon 2754 3700 . + . gene_id "ND1"; transcript_id "cds-YP_007626758.1"; Parent "gene-ND1"; Dbxref "Genbank:YP_007626758.1,Gene "ID:15088436"; Name "YP_007626758.1"; Note "TAAstopcodoniscompletedbytheadditionof3'AresiduestothemRNA"; gbkey "CDS"; gene "ND1"; product "NADHdehydrogenasesubunit1"; protein_id "YP_007626758.1"; transl_except "(pos:3700..3700%2Caa:TERM)"; transl_table "2";
답변2
우리는 주어진 키에 여러 값이 적용되면 마지막 값이 최종 값이 되는 해시의 속성을 활용합니다.
perl -lpe 'my($l,%h)=($_);
$h{gene_id}=$_ for map {
$l =~ /\b$_\s+(".*?");/
} reverse qw(gene product sprot);
s/\bgene_id\s+\K".*?";/$h{gene_id};/;
' your_file_genes
명령은 모두 동일하고 이름만 변경되므로 전체 작업 테이블을 쉽게 구동할 수 있습니다. 여기서는 필드 이름만 제공하고 for 루프가 나머지를 처리합니다.
for i in gene product sprot;do
cat - <<\_FMT_ |\
sed -e "s/%s/$i/"
s/(\<gene_id\s+)"[^"]*"(.*\s%s\s+("[^"]*"))/\1\3\2/;t
_FMT_
done | sed -Ef - your_file_genes
답변3
솔루션 을 완성하려면 를 사용하여 perl
수행하는 방법은 다음과 같습니다 sed
. 주어진 구문이 어떻게 작동할지 잘 모르겠지만 실제로는 문자열과 일치하는 정규식이 필요합니다.
... gene_id "remove me" ... some other stuff gene "replacement" ... more stuff
======= ====
gene_id "[^"]*" .* gene "[^"]*"
gene_id
그리고 gene
스스로 일치합니다. 큰따옴표 안의 문자열은 큰따옴표, 큰따옴표가 아닌 문자 수( [^"]*
) 및 다른 큰따옴표를 연결한 것입니다. 마지막으로 그 사이에 물건이 있습니다..*
\(\)
이제 교체 시 재활용해야 하는 부품을 배치 해야 합니다 .
sed 's/gene_id "[^"]*"\(.* gene \("[^"]*"\)\)/gene_id \2\1/'
외부 쌍은 그대로 두어야 할 모든 것을 포함합니다. 이는 \1
교체와 마찬가지로 재사용됩니다. 내부 쌍은 재사용하려는 문자열입니다 gene_id
.
product
이제 또는 대체 대체품을 원할 경우 sprot
확장 정규식의 대체 문자열을 사용할 수 있습니다.
sed -E 's/gene_id "[^"]*"(.*(gene|product|sprot) ("[^"]*"))/gene_id \3\1/'
그러나 이는 gene
over product
를 선호하지 sprot
않고 존재하는 마지막 항목을 선호합니다. 해당 우선 순위를 원할 경우 별도의 단계가 필요하며 마지막 단계부터 시작하여 더 나은 단계로 대체할 수 있습니다.
sed 's/gene_id "[^"]*"\(.* sprot \("[^"]*"\)\)/gene_id \2\1/
s/gene_id "[^"]*"\(.* product \("[^"]*"\)\)/gene_id \2\1/
s/gene_id "[^"]*"\(.* gene \("[^"]*"\)\)/gene_id \2\1/'
gene
또는 , sprot` 의 순서가 product
고정되어 있는 것으로 알려진 경우 홀드 공간에 실제 라인을 주차하면서 먼저 선호 ID를 추출할 수 있습니다.
sed -E 'h;s/(sprot|product|gene) ("[^"]*").*/#\2/;s/.*#//;G;s/(.*)\n(.*gene_id )"[^"]*"/\2\1/'
마커는 #
ID의 일부가 아닌 것으로 알려진 문자열일 수 있습니다. GNU의 경우 확실하게 sed
사용할 수 있습니다 . \n
따라서 해당 문자열 중 첫 번째를 마커로 바꾸고 나머지 줄을 삭제한 다음 마커까지 모든 것을 삭제하므로 이제 패턴 공간에는 ID만 남게 됩니다. 그런 다음 G
원래 줄( 를 사용하여 보류 버퍼에 보존한 h
)이 추가되고 ID(개행 앞 부분)가 "string"
이후를 대체합니다 gene_id
. 설명하는 것보다 쓰는 것이 더 쉽습니다.