Печать позиции символов перекрывающихся строк, хранящихся в циклической переменной, с использованием grep? - PullRequest
2 голосов
/ 08 марта 2019

У меня действительно длинная строка (хранится в файле), заполненная буквами B и E, и я пытаюсь получить информацию о положении в этом файле для всех совпадений для серии паттернов, по которым я зацикливаюсь.Я довольно близок к тому, чтобы заставить его работать, но проблема в том, что я пропускаю случаи перекрывающихся совпадений с использованием grep.

Например, список шаблонов и строк, которые я ищу, выглядят так:

$cat CNVE_list.txt
BEEBB
BBBBEE
EEEEE
BEEEBBBBB

$cat probe_profile.txt
BBBEBEEBEEEEEEBBEEBBBB

И цикл, который я пытаюсь запустить, выглядит следующим образом

filename='CNVE_list.txt'
while read p; do 
    echo $p | grep -aob -f - probe_profile.txt > probe_profile_$p.txt   
done < $filename

Проблема в этом примере связана со строкой 3 в файле CNVE_list.txt (EEEEE).Он должен иметь два перекрывающихся совпадения, но находит только первое.Я прочитал некоторые другие вопросы и обнаружил, что проблема решена с помощью PERL с помощью стратегии поиска за спиной, но не уверен, как решить эту проблему с помощью зацикленных переменных.

, т.е. https://unix.stackexchange.com/questions/276159/grep-that-works-with-overlapping-patterns

Я имею делос очень длинным списком шаблонов и очень длинной строкой, поэтому чем эффективнее, тем лучше.Заранее спасибо за помощь!

Ответы [ 2 ]

0 голосов
/ 08 марта 2019

Используя Perl и позитивный прогноз,

perl -lne ' BEGIN { @pat=map{ chomp;$_} qx(cat CNVE_list.txt); } 
       { for my $p (@pat) { while(/(?=$p)/g) { print $p } }} ' probe_profile.txt

Результаты:

$ perl -lne ' BEGIN { @pat=map{ chomp;$_} qx(cat CNVE_list.txt); } 
      { for my $p (@pat) { while(/(?=$p)/g) { print $p } }} ' probe_profile.txt
BEEBB
EEEEE
EEEEE

$

РЕДАКТИРОВАТЬ1:

Кполучить позиции совпадения

$ perl -lne ' BEGIN { @pat=map{ chomp;$_} qx(cat CNVE_list.txt); } 
  { for my $p (@pat) { while(/(?=$p)/g) { print "$-[0], $p" } }} ' probe_profile.txt
15, BEEBB
8, EEEEE
9, EEEEE

$

EDIT2:

Проверьте ниже оптимизированный.

$ perl -lne ' BEGIN { @pat=map{ chomp;$_} qx(cat CNVE_list.txt); 
   $p="(".join("\|",sort { length($b) <=> length($a) } @pat).")" } {  
       while(/(?=$p)/g) { print "$-[0], $1" } } ' probe_profile.txt
8, EEEEE
9, EEEEE
15, BEEBB

$
0 голосов
/ 08 марта 2019

Использование awk.Я не думаю, что это будет медленнее, чем grep, но оно не молниеносно (хотя и не проверялось ни с чем, кроме предоставленных образцов):

awk 'NR==FNR{
    a[$0]                                # hash search strings to a
    next
}
{
    print ++c ". string:"                # 1. is string, 2. is string reversed
    b=$0                                 # string to b
    for(i in a) {                        # loop all search words
        k=1                              # reset index 
        while(j=index(substr(b,k),i)) {  # search 
            print i,k+j-1                # output search word and index
            k=k+j                        
        }
    }
}' list profile <(rev profile)

Вывод:

1. string:
BEEBB 16
EEEEE 9
EEEEE 10
2. string:
BEEBB 4
BBBBEE 1
EEEEE 9
EEEEE 10

Он использует команду rev для изменения профиля (и bash).

Обновление :

Я протестировал решение grep в OP, решение perl @ stack0114106 и мой awkс 120000 символами случайных B и Es в profile и 1000 предметов длиной 10-50 в list:

OP (лучшее время из трех для всех):

hits: 4506

real    0m3.977s
user    0m1.500s
sys     0m0.436s

GNU awk (без rev):

4511

real    0m2.576s
user    0m2.576s
sys     0m0.000s

Mawk (без оборотов):

4511

real    0m1.694s
user    0m1.692s
sys     0m0.000s

Perl:

4511

real    0m10.371s
user    0m10.360s
sys     0m0.008s
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...