SED: несколько шаблонов в одной строке, как совместить/разбор сначала
У меня есть файл, содержащий данные телефонного номера, а также некоторые бесполезные вещи.
Я пытаюсь разобрать цифры, и когда есть только 1 номер телефона/линии, это не проблема.
Но когда у меня есть несколько номеров, sed соответствует последнему (хотя везде он говорит, что он должен соответствовать только совпадению первого шаблона?), И я не могу получить другие номера.
Мой data.txt:
bla bla bla NUM:09011111111 bla bla bla bla NUM:08022222222 bla bla bla
Когда я анализирую данные, моя идея была сначала удалить все "начальные" "bla bla bla" перед первым номером телефона (так что я ищу первое появление "NUM:" ), затем я удаляю все вещи после номера телефона, и получите номер.
После этого я хочу проанализировать следующее возникновение из оставшейся строки.
Итак, теперь, когда я пытаюсь установить его, я всегда получаю последнее число на линии:
>sed 's/.*NUM://' data.txt
08022222222 bla bla bla
>
В первую очередь я хотел бы понять, что неправильно с моим пониманием SED. Конечно, более эффективные предложения приветствуются!
Не говорит ли моя команда sed, замените все вещи до "NUM:" на "" (пустой)? Почему он всегда совпадает с последним событием?
Спасибо!
Ответы
Ответ 1
Это может сработать для вас:
echo "bla bla bla NUM:09011111111 bla bla bla bla NUM:08022222222 bla bla bla" |
sed 's/NUM:/\n&/g;s/[^\n]*\n\(NUM:[0-9]*\)[^\n]*/\1 /g;s/.$//'
NUM:09011111111 NUM:08022222222
У вас есть понимание того, что .*
жадный, т.е. он соответствует самому длинному совпадению, а не первому совпадению. Поместив уникальный символ (\n
sed использует его как разделитель строк, чтобы он не существовал в строке) перед интересующей нас строкой (NUM:...
) и удалением всего, что не является уникальным символом [^\n]*
, за которым следует уникальный символ \n
, мы эффективно разделяем строку на управляемые части.
Ответ 2
Как вы уже знаете, регулярные выражения sed
являются жадными, и, насколько я могу судить, нельзя сделать неживыми.
Две альтернативы, которые не были доведены до сих пор, - это просто использовать другие инструменты для такого соответствия/извлечения.
Вы можете использовать perl
как замену для sed с параметрами -pe
. Он поддерживает ?
неживой модификатор:
$ perl -pe 's/.*?NUM://' data.txt
09011111111 bla bla bla bla NUM:08022222222 bla bla bla
Вы можете использовать параметр -o
для GNU grep, чтобы получить только биты ваших данных, которые соответствуют регулярному выражению:
$ egrep -o 'NUM:[0-9]*' data.txt
NUM:09011111111
NUM:08022222222
Ответ 3
Если число определяется цифрами, следующими за NUM:
:
sed -n -e 's/$/\n/' -e ':begin' \
-e 's/\(NUM:[0-9][0-9]*\)\(.*\)\n\(.*\)/\2\n\3 \1/' \
-e 'tbegin' -e 's/.*\n //' -e '/NUM/p'
Что это такое:
- Поместите a
\n
в конце строки, чтобы действовать как маркер.
- Попробуйте найти номер перед маркером и поместите его в конец строки (после маркера).
- Если число было найдено, перейдите выше 2.
- Когда перед маркером не осталось числа, удалите все перед номерами.
- Если номер находится в строке, напечатайте его (чтобы обработать случай, когда число не найдено.
Это также можно сделать наоборот, сначала вычеркивая строки без цифр:
sed -e '/NUM/!d' -e 's/$/\n/' -e ':begin' \
-e 's/\(NUM:[0-9][0-9]*\)\(.*\)\n\(.*\)/\2\n\3 \1/' \
-e 'tbegin' -e 's/.*\n //'
Ответ 4
Вы можете использовать этот шаблон:
sed -r 's/^(.*NUM:)(.*NUM:.*)$/\2/'