2017-02-15 22 views
1

у меня есть набор данных с двумя столбцами:Поиск нескольких вхождений одного выражения в строке

  1. десятичное число
  2. длинную строку

Со второй колонке я хотел бы для извлечения каждого номера FBtr (например, FBtr0072798) и игнорирования остальных.

0.850359 EFF=INTRON(MODIFIER|||||drpr|||FBtr0072798|4|1),INTRON(MODIFIER|||||drpr|||FBtr0072799|4|1),INTRON(MODIFIER|||||drpr|||FBtr0309845|4|1),SYNONYMOUS_CODING(LOW|SILENT|atT/atA|I690||CG18171|||FBtr0072800|1|1) 
0.473555 EFF=INTRON(MODIFIER|||||drpr|||FBtr0072798|4|1),INTRON(MODIFIER|||||drpr|||FBtr0072799|4|1),INTRON(MODIFIER|||||drpr|||FBtr0309845|4|1),SYNONYMOUS_CODING(LOW|SILENT|agC/agT|S371||CG18171|||FBtr0072800|1|1),UPSTREAM(MODIFIER|||||CG12035|||FBtr0072766||1) 
0.969735 EFF=INTRON(MODIFIER|||||drpr|||FBtr0072798|4|1),INTRON(MODIFIER|||||drpr|||FBtr0072799|4|1),INTRON(MODIFIER|||||drpr|||FBtr0309845|4|1),SYNONYMOUS_CODING(LOW|SILENT|gtT/gtC|V366||CG18171|||FBtr0072800|1|1),UPSTREAM(MODIFIER|||||CG12035|||FBtr0072766||1) 

Я хотел бы в конце концов, чтобы перенести это в длинный формат, так что каждая строка содержит десятичное число от первого столбца, в паре с одним номером FBTR. Например,

0.850359 FBtr0072798 
0.850359 FBtr0072799 
0.850359 FBtr0309845 
0.850359 FBtr0072800 
0.473555 FBtr0072798 
0.473555 FBtr0072799 
0.473555 FBtr0309845 
0.473555 FBtr0072800 
0.473555 FBtr0072766 
0.969735 FBtr0072798 
0.969735 FBtr0072799 
0.969735 FBtr0309845 
0.969735 FBtr0072800 
0.969735 FBtr0072766 

Я пытаюсь сделать это в ступенчатом образе, первое экстрагированием числа FBTR в отдельную колонку:

0.850359 FBtr0072798 FBtr0072799 FBtr0309845 FBtr0072800 
0.473555 FBtr0072798 FBtr0072799 FBtr0309845 FBtr0072800 FBtr0072766 
0.969735 FBtr0072798 FBtr0072799 FBtr0309845 FBtr0072800 FBtr0072766 

Тогда переходя от широких к длинному формату.

Прямо сейчас у меня возникают проблемы с извлечением номера FBtr. Я все больше новичок на python, чем unix, поэтому я пытался использовать unix, потому что я немного более удобен в отношении языка. Самая многообещающая вещь, которую я пробовал до сих пор, использует sed, чтобы выполнять поиск/замену для каждого из терминов повторно.

sed -e 's/\(.* \).*\(FBtr[0-9]*\).*\(FBtr[0-9]*\).*\(FBtr[0-9]*\).*\(FBtr[0-9]*\).*\(FBtr[0-9]*\).*/ \1 \2 \3 \4 \5 \6/ g' file.txt 

Это не только некрасиво со всеми повторами, но работает только если есть такое же количество FBTR вхождений в строке, которые, к сожалению, не являются. Любые мысли о том, как подойти к этой проблеме в unix или python?

+0

Если вы можете использовать 'GNU Awk', см. Мой ответ ниже. – Inian

ответ

1

Вот небольшая программа python, которая, как я думаю, соответствует вашим требованиям. Он использует str.split() и str.startswith(), чтобы найти все вхождения строк, начиная с FBtr.

Код:

for line in test_data: 
    num, string = line.split(' ', 1) 
    for field in string.split('|'): 
     if field.startswith('FBtr'): 
      print(num, field) 

Тестовые данные:

test_data = [x.strip() for x in """ 
    0.850359 EFF=INTRON(MODIFIER|||||drpr|||FBtr0072798|4|1),INTRON(MODIFIER|||||drpr|||FBtr0072799|4|1),INTRON(MODIFIER|||||drpr|||FBtr0309845|4|1),SYNONYMOUS_CODING(LOW|SILENT|atT/atA|I690||CG18171|||FBtr0072800|1|1) 
    0.473555 EFF=INTRON(MODIFIER|||||drpr|||FBtr0072798|4|1),INTRON(MODIFIER|||||drpr|||FBtr0072799|4|1),INTRON(MODIFIER|||||drpr|||FBtr0309845|4|1),SYNONYMOUS_CODING(LOW|SILENT|agC/agT|S371||CG18171|||FBtr0072800|1|1),UPSTREAM(MODIFIER|||||CG12035|||FBtr0072766||1) 
    0.969735 EFF=INTRON(MODIFIER|||||drpr|||FBtr0072798|4|1),INTRON(MODIFIER|||||drpr|||FBtr0072799|4|1),INTRON(MODIFIER|||||drpr|||FBtr0309845|4|1),SYNONYMOUS_CODING(LOW|SILENT|gtT/gtC|V366||CG18171|||FBtr0072800|1|1),UPSTREAM(MODIFIER|||||CG12035|||FBtr0072766||1) 
""".split('\n')[1:-1]] 

дает выход:

0.850359 FBtr0072798 
0.850359 FBtr0072799 
0.850359 FBtr0309845 
0.850359 FBtr0072800 
0.473555 FBtr0072798 
0.473555 FBtr0072799 
0.473555 FBtr0309845 
0.473555 FBtr0072800 
0.473555 FBtr0072766 
0.969735 FBtr0072798 
0.969735 FBtr0072799 
0.969735 FBtr0309845 
0.969735 FBtr0072800 
0.969735 FBtr0072766 
1
import re 
line = '0.850359 EFF=INTRON(MODIFIER|||||drpr|||FBtr0072798|4|1),INTRON(MODIFIER|||||drpr|||FBtr0072799|4|1),INTRON(MODIFIER|||||drpr|||FBtr0309845|4|1),SYNONYMOUS_CODING(LOW|SILENT|atT/atA|I690||CG18171|||FBtr0072800|1|1)' 
print(re.findall('FBtr(\d+)', line)) 

[ '0072798', '0072799', '0309845', '0072800']

+0

Привет, не могли бы вы рассказать о своем предлагаемом ответе? Как сейчас, трудно понять, почему это работает. –

+0

[re.findall()] (https://docs.python.org/3.6/library/re.html#re.findall) просто находит все вхождения regexp в строке и возвращает их как список –

+0

, если вы меняете regexp на Результатом '' (FBtr) (\ d +) ''будет' [(' FBtr ',' 0072798 '), (' FBtr ',' 0072799 '), (' FBtr ',' 0309845 '), (' FBtr ' , '0072800')] ' –

2

Если вы можете использовать GNU Awk свою gensub() функцию может быть прохладно, чтобы сделать жизнь проще, для вас,

awk -F[[:space:],] '{for(i=1;i<=NF;i++) if (match($i,/FBtr([[:digit:]]+)/)) \ 
    {value=gensub(/^.*FBtr([[:digit:]]+).*$/,"FBtr\\1","g",$i); print $2,value} }' file 
0.850359 FBtr0072798 
0.850359 FBtr0072799 
0.850359 FBtr0309845 
0.850359 FBtr0072800 
0.473555 FBtr0072798 
0.473555 FBtr0072799 
0.473555 FBtr0309845 
0.473555 FBtr0072800 
0.473555 FBtr0072766 
0.969735 FBtr0072798 
0.969735 FBtr0072799 
0.969735 FBtr0309845 
0.969735 FBtr0072800 
0.969735 FBtr0072766 
+0

Я не уверен, что это * просто *, но, похоже, работает с одной настройкой - напечатайте $ 1 вместо $ 2. Спасибо! – user4670961

2

Это может работать для вас (GNU СЭД):

sed -r '/\n/!s/FB[^|]*/\n&\n/g;s/^\s*(\S+)[^\n]*\n([^\n]*\n)/\1 \2\1 /;/FB/P;D' file 

Изолировать FB строки с помощью новой строки.Затем, используя совпадающие и обратные ссылки, создайте первую запись и запустите вторую, напечатайте только строки, содержащие строки FB, и повторите, пока вся текущая строка не будет полностью обработана.