2013-04-05 4 views
1

У меня есть один массив, заполненный короткими строками (@pos) и второй большой массив (@exome). Я хочу искать второй массив для любого совпадения со строками из первого. Цель состоит в том, чтобы напечатать все строки из @exome, которые имеют спичкуPerl grep два массива

Im используя Perl это то, что я до сих пор

#!/usr/bin/perl 
use strict; use warnings; 

my $pos = $ARGV[0]; 
my $exome = $ARGV[1]; 

open (F, "$pos") || die "Could not open $pos: $!\n"; 
my @pos = <F>; 
close F; 

open (F, "$exome") || die "Could not open $exome: $!\n"; 
my @exome = <F>; 
close F; 

foreach (@pos) { 
    my @out = grep(/$_/, @exome); 
    print @out 
} 
+3

Что ваш вопрос? – mob

+0

@JoeFrambach: Это не вопрос. Какой у Вас вопрос? – Borodin

ответ

1

Я думал @ikegami выдал довольно хороший ответ, НО, он, кажется, чтобы получить ошибки в том, что массив для печати ... Может @ user2249959 хочет массив @exome не для печати ... основной код нужен не больше, чем две строки:

my $grep_pos = join '|', @pos; 
my @matched_results = grep { /$grep_pos/ } @exome; 

Ну, вы можете распечатать сразу на второй линии, но не будет иметь пустое пространство между элементами в массив. Две петли foreach не похожи на Perl, только по моему мнению ...

P.S. Я добавил три очка, чтобы обратить внимание
1. Будьте осторожны с невидимыми «\ n» или «\ r \ n»
2. Будьте осторожны с белым пространством в начале и конце каждой строки.
Вы можете решить вышеуказанные две точки с простыми кодами, например:

map { chomp; s/^\s*|\s*$// } @pos; 

Это приведет к удалению «\ п» (если есть), и белые пространства впереди или в конце (если предположить, что бессмысленно). Сделайте это перед grep
3. БОЛЬШЕ ВАЖНО! Будьте осторожны с пустыми строками в файле массива @pos!
Если ваш файл выглядит следующим образом:

pos_1 
pos_2 
<---- totally blank 
pos_3 

Если вы все-таки присоединиться к линии вместе с «|», он станет «pos_1 | pos_2 || pos_3», это означает, что что-то в @exome будет соответствовать. (Из-за «||»)
Chomp или с /// не поможет, вы должны прыгать эту линию самостоятельно
Просто будьте осторожны :)

+0

Спасибо.Но это, кажется, не будет работать, если есть какие-либо символы после строки то будет соответствовать например Pos: ExoME: 1234AB не будет соответствовать. AB1234. Есть идеи? –

+0

@ user2249959, Может быть, я знаю, что произошло. Вот моя догадка: читаете ли вы массив pos и exome из файла? Тогда значение 1234 должно быть как «1234 \ n», оно содержит невидимый символ в хвосте. Таким образом, «1234AB \ n» не будет соответствовать, но «AB» добавлено в голову («AB1234 \ n») по-прежнему соответствует «1234 \ n». Я также изменю свой код, так как обнаружил очень неудобную ошибку. – noalac

+0

Отлично, спасибо. Прекрасно работает. –

2

Проблемы:

  • /$_/ означает $_ =~ /$_/, поэтому, возможно, вы должен использовать другую переменную для шаблона.
  • Вы не преобразуете текст в шаблон регулярного выражения (что можно сделать с помощью quotemeta)
  • Вы можете вывести одну и ту же строку дважды.
  • Пожалуйста, не используйте глобальные вары для дескрипторов файлов.
  • Не нужно загружать весь файл, находящийся в памяти.

Решение:

my ($pos_qfn, $exome_qfn) = @ARGV; 

open(my $pos_fh, '<', $pos_qfn) 
    or die("Could not open $pos_qfn: $!\n"); 
my @pos = <$pos_fh>; 
chomp(@pos); 

my $pat = join '|', map quotemeta, @pos; 

open(my $exome_fh, '<', $exome_qfn) 
    or die("Could not open $exome_qfn: $!\n"); 

while (<$exome_fh>) { 
    print if /$pat/; 
} 
+0

@TLP, Действительно, исправлено. – ikegami

+0

Я думаю, что ваш код компилирует соответствующий шаблон в каждом вызове. Просто добавив '$ pat = qr/$ pat /;' после объединения, нужно решить проблему. –