сопоставление нескольких шаблонов несколько раз с записью с помощью awk

Я пытаюсь эффективно сопоставлять несколько шаблонов одновременно, что в принципе работает очень хорошо:

echo abcdef | awk \
'/abc/ {print "match abc"}
 /def/ {print "match def"}'

Кроме того, я хочу сопоставить все вхождения в записи:

echo abcabc | awk \
'function findall(str, re) {
    while(match(str, re)) {
        print "match", re;
        str = substr(str, RSTART+RLENGTH)
    }
}
{
    findall($0, "abc");
}'

Теперь, чтобы расширить приведенный выше пример, чтобы он соответствовал нескольким шаблонам, я бы закончил серию вызовов findall:

findall($0, "abc");
...
findall($0, "def");

Проблема в том, что при множестве разных шаблонов (>100) этот подход не работает так же хорошо, как первый пример. Что имеет смысл, поскольку я думаю, что шаблон не попадает в один и тот же автомат.

Есть ли способ немного ускорить процесс? например обеспечение «совпадения» с несколькими шаблонами. Думаю, я мог бы соединить шаблоны (abc|def), но тогда я потерял бы информацию о том, какой именно шаблон совпал.

Обновление: каждое вхождение должно быть сопоставлено:

abcabc
123
abcxyz

поскольку входные данные приводят к двум совпадающим записям (учитывая стандартный разделитель), но четырём совпадениям во всех данных при использовании с шаблонами "abc" и "xyz". Первый образец в этом посте сообщает как минимум 3 совпадения, но не обнаруживает несколько вхождений "abc" в первой записи.


person Joe    schedule 28.02.2012    source источник
comment
Мне нужна дополнительная информация 1. что нужно, если шаблоны перекрываются? например, когда вы пытаетесь сопоставить /abc|ca/ в abcabc? 2. Ваши шаблоны такие же простые, как в посте (простые последовательности букв)? без операторов количества, диапазонов символов?   -  person Nik O'Lai    schedule 02.03.2012


Ответы (1)


как насчет сделать это таким образом:

вы помещаете свои шаблоны в файл, каждый шаблон в строку, а не в функцию awk.

e.g.

kent$  cat p.txt
abc
def
foo
xxx

затем вы можете загрузить файл и позволить awk выполнить соответствующую работу за вас. в конце распечатайте только те шаблоны, которые соответствуют вашей входной строке:

    echo inputString|awk 'NR==FNR{ps[$0]=0;next;}
{for(p in ps)if(match($0,p))ps[p]++;}
END{for(p in ps) if(ps[p]>0)print p" matched"}' p.txt -

конечно, вы можете заменить «-» входным файлом, если вам нужно.

небольшой тест:

kent$  echo "abcdefoobarblah"|awk 'NR==FNR{ps[$0]=0;next;}{for(p in ps)if(match($0,p))ps[p]++;}END{for(p in ps) if(ps[p]>0)print p" matched"}' p.txt -
def matched
foo matched
abc matched

значит, шаблон "xxx" не совпал. были распечатаны только def,foo,abc.

Обратите внимание, что сценарий можно оптимизировать и сделать короче. например, сохраните блок END{}, выполните печать в первом цикле for. тем не менее, это показывает вам мою идею, как с этим поступить.

ИЗМЕНИТЬ комментарий ОП

Джо, я не увидел требования совпадения времени в твоем вопросе. однако добиться этого нетрудно. См. приведенный ниже тест с текстом примера:

kent$  echo "abcabcabcdefoobarblah"|
awk 'NR==FNR{ps[$0]=0;next;}
{for(p in ps){t=$0;ps[p]=gsub(p,"",t);}}
END{for(p in ps) if(ps[p]>0)print p" matched "ps[p]" time(s)"}' p.txt -

вывод:

def matched 1 time(s)
foo matched 1 time(s)
abc matched 3 time(s)
person Kent    schedule 28.02.2012
comment
Это не соответствует каждому вхождению шаблонов в каждой записи. echo "abcabcabcdefoobarblah"|awk 'NR==FNR{ps[$0]=0;next;}{for(p in ps)if(match($0,p))ps[p]++;}END{for(p in ps) if(ps[p]>0)print p" matched "ps[p]" time(s)"}' p.txt - утверждает, что abc был найден один раз, хотя в записи он встречается 3 раза. Использование findall в вашем коде снова возвращает нас к нашей первоначальной проблеме:/ - person Joe; 28.02.2012
comment
Обновление дает ожидаемый результат, но страдает тем же недостатком производительности, что и адаптация findall. - person Joe; 28.02.2012