Регулярное выражение с awk или gawk

Я начинающий пользователь awk/gawk. Если я бегу ниже, оболочка мне ничего не дает. Пожалуйста помоги!

echo "A=1,B=2,3,C=,D=5,6,E=7,8,9"|awk 'BEGIN{
n = split($0, arr, /,(?=\\w+=)/)
for (x=1; x<n; x++) printf "arr[%d]=%s\n", x, arr[x]
}'

.....................................................

Я пытаюсь разобрать:

A=1,B=2,3,C=,D=5,6,E=7,8,9

Ожидаемый результат:

A=1
B=2,3
C=
D=5,6
E=7,8,9

Бьюсь об заклад, что-то не так с моим awk.


person Jaeh    schedule 07.02.2013    source источник
comment
В awk нет упреждающего просмотра, IIRC.   -  person nhahtdh    schedule 08.02.2013
comment
Хороший вопрос с самодокументируемым тестовым примером. Продолжайте публиковать и удачи!   -  person shellter    schedule 08.02.2013


Ответы (7)


gawk не поддерживает просмотр вперед.

если вы хотите, чтобы gawk анализировал его так, как вы ожидали, попробуйте следующее:

awk '{n=split(gensub(/,([A-Z])/, " \\1","g" ),arr," ");for(x=1;x<=n;x++)print arr[x]}'

проверить на своем примере:

kent$  echo "A=1,B=2,3,C=,D=5,6,E=7,8,9"|awk '{n=split(gensub(/,([A-Z])/, " \\1","g" ),arr," ");for(x=1;x<=n;x++)print arr[x]}'
A=1
B=2,3
C=
D=5,6
E=7,8,9
person Kent    schedule 07.02.2013
comment
О, мне это нравится. Я пытался понять, как разделить, но я не подумал об использовании gensub() и использовании обратной ссылки, чтобы сохранить ту часть, которую мы хотим сохранить. +1. - person steveha; 08.02.2013
comment
@steveha, спасибо. первым подошел sed -r 's/,([A-Z])/ \1/g'|awk 'simple split..', но я подумал, что было бы неплохо писать в одном процессе. - person Kent; 08.02.2013

Это может быть проще с sed:

$ echo "A=1,B=2,3,C=,D=5,6,E=7,8,9" | sed 's/,\(\w\+=\)/\n\1/g'
A=1
B=2,3
C=
D=5,6
E=7,8,9
person Andrew Clark    schedule 07.02.2013

Если вы используете gnu awk, вы можете сделать:

awk '{printf $0 "\n" substr( RT, 2 )}' RS=,[A-Z]
person William Pursell    schedule 08.02.2013
comment
Я также думал об использовании RS, но не знал, как получить этот текст с помощью RT :) - person Mirage; 09.02.2013

Как и nhahtdh, в awk нет функции просмотра вперед... Но вы можете использовать другой разделитель для заданий. Почему бы не "A=1;B=2,3,4;C=5..."? Если ваш ввод должен иметь этот формат, попробуйте flex...

person Rui Brito    schedule 07.02.2013

Вы также можете использовать запятую в качестве разделителя record:

echo "A=1,B=2,3,C=,D=5,6,E=7,8,9" |
awk -v RS=, '{sep=","} /=/ {sep="\n"} NR==1 {sep=""} {printf "%s%s", sep, $0}'

выходы

A=1
B=2,3
C=
D=5,6
E=7,8,9
person glenn jackman    schedule 07.02.2013

У вас есть две проблемы. Во-первых, вам не нужен пункт BEGIN; вы просто хотите, чтобы это выполнялось в каждой строке ввода. Во-вторых, вы пытаетесь использовать функции регулярных выражений, которые не поддерживает AWK.

Вместо того, чтобы пытаться использовать причудливый шаблон, который разбивает строку, зациклируйте и вызовите match(), чтобы проанализировать нужные вам функции.

echo "A=1,B=2,3,C=,D=5,6,E=7,8,9"|awk '
{
    line = $0
    for (i = 0;;)
    {
        i = match(line, /([A-Z]+)=([0-9,]*)(,|$)/, arr)
        if (0 == i)
            break
        key = arr[1]
        value = arr[2]
        l = length(key "=" value ",") + 1
        line = substr(line, l)
        printf "DEBUG: key '%s' value '%s'\n", key, value
    }
}'

Это печатает:

DEBUG: key A value 1
DEBUG: key B value 2,3
DEBUG: key C value
DEBUG: key D value 5,6
DEBUG: key E value 7,8,9
person steveha    schedule 07.02.2013

Другой способ использования awk

awk '{print gensub(/,([A-Z]+=)/, "\n\\1","g")}' temp.txt

Выход

A=1
B=2,3
C=
D=5,6
E=7,8,9
person Mirage    schedule 08.02.2013