awk извлекает несколько групп из каждой строки

Как выполнить действие для всех подходящих групп, если шаблон совпадает несколько раз в строке?

Чтобы проиллюстрировать, я хочу найти /Hello! (\d+)/ и использовать числа, например, распечатать их или сложить их, так что для ввода

abcHello! 200 300 Hello! Hello! 400z3
ads
Hello! 0

Если бы я решил распечатать их, я бы ожидал вывод

200
400
0

4 ответа

Решение

Это простой синтаксис, и каждый awk (nawk, mawk, gawk и т. Д.) Может использовать это.

{
    while (match($0, /Hello! [0-9]+/)) {
        pattern = substr($0, RSTART, RLENGTH);
        sub(/Hello! /, "", pattern);
        print pattern;
        $0 = substr($0, RSTART + RLENGTH);
    }
}

Это gawk синтаксис. Это также работает для шаблонов, когда нет фиксированного текста, который может работать как разделитель записей и не совпадает с переводом строки:

 {
     pattern = "([a-g]+|[h-z]+)"
     while (match($0, pattern, arr))
     {
         val = arr[1]
         print val
         sub(pattern, "")
     }
 }

GNU awk

awk 'BEGIN{ RS="Hello! ";}
{
    gsub(/[^0-9].*/,"",$1)
    if ($1 != ""){ 
        print $1 
    }
}' file

Не существует функции gawk для сопоставления одного и того же шаблона несколько раз в строке. Если вы точно не знаете, сколько раз шаблон повторяется.

Имея это, вы должны выполнить итерацию "вручную" для всех совпадений в одной строке. Для вашего примера ввода это будет:

{
  from = 0
  pos = match( $0, /Hello! ([0-9]+)/, val )
  while( 0 < pos )
  {
    print val[1]
    from += pos + val[0, "length"]
    pos = match( substr( $0, from ), /Hello! ([0-9]+)/, val )
  }
}

Если шаблон должен совпадать с переводом строки, вы должны изменить разделитель входной записи - RS

Другие вопросы по тегам