Подтвердить что ты не робот

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:" на "" (пустой)? Почему он всегда совпадает с последним событием?

Спасибо!

4b9b3361

Ответ 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/'