4

Представьте, что у меня есть что-то вроде следующего текста:

Быстрый бурый лис прыгает в 2012 и 2013 годах

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

Быстрый коричневый и 2013

Как то так ...

echo "The quick brown fox jumps in 2012 and 2013" \
   | sed  "s/fox.*\([0-9]\{4\}\)//g"

... приносит мне:

The quick brown

Таким образом, он удалил все, включая последнее появление четырех чисел.

Есть идеи?

3 ответа3

6

Регулярные выражения POSIX, используемые sed (как "базовая", так и "расширенная" версии), не поддерживают не жадные совпадения. (Хотя есть некоторые обходные пути, такие как использование [^0-9]* вместо .* , Они становятся ненадежными, если входные данные сильно различаются.)

Чего вам нужно достичь в Perl с помощью ? не жадный квантификатор:

echo "The quick brown fox jumps in 2012 and 2013" \
   | perl -pe 's/fox.*?([0-9]{4})//g'

Вы можете также удалить дополнительное пространство.

1

Предполагая, что вы хотите использовать только sed и хотите, чтобы конец совпадения был первой группой цифр, не обращая внимания на то, что это за слово после цифр, это работает:

echo "The quick brown fox jumps in 2012 and 2013" \
   | sed "s/fox[^0-9][^0-9]*[0-9][0-9]* //"

Шаблон работает путем сопоставления fox , за которым следуют одна или несколько не цифр [^0-9][^0-9]* , за которыми следуют 1 или более цифр [0-9][0-9]* . Этот шаблон будет работать с произвольным числом цифр, а не только с 4. Если вы хотите точно соответствовать 4 цифрам, измените его на:

echo "The quick brown fox jumps in 2012 and 2013" \
   | sed "s/fox[^0-9]*\([0-9]\{4\}\) //"
1

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

echo "The quick brown fox jumps over 42 lazy dogs in 2012 and 2013." \
  | sed \
        -e "s/[0-9]\{4\}/###/" \
        -e "s/fox.*####//" \
        -e "s/####//"

(Команды чрезмерно сложены для удобства чтения.)  -e "s/[0-9]\{4\}/&####/" вставляет #### после первого четырехзначного числа. (Предупреждение: это изменит 65536 на 6553####6 )
-e "s/fox.*####//" затрагивает строки, содержащие fox и #### - то есть строки, которые содержат как минимум одно четырехзначное число, а затем удаляет из fox через первые четыре -значный номер.
-e "s/####//" , конечно, очищает любые строки #### , которые остались от строк, которые содержат четырехзначное число, но не fox .

Чтобы также удалить один пробел после числа, если есть,

echo "The quick brown fox jumps over 42 lazy dogs in 2012 and 2013." \
  | sed \
        -e "s/[0-9]\{4\}/###/" \
        -e "s/fox.*#### //" \
        -e "s/fox.*####//" \
        -e "s/####//"

Предупреждение: Вы можете добавить g ко всем командам s , но, поскольку он все еще использует .* , Который является корнем вашей проблемы, он все равно не будет обрабатывать

One fox jumps in 2012 and 2013, another fox will jump in 2014 and 2015.

так, как вы, вероятно, хотите.  И, конечно, вы не хотите добавлять g в "s/[0-9]\{4\}/&####/" потому что тогда он будет вводить #### после каждого четырехзначного числа , победив весь смысл.  Тогда "s/fox.*####//" конечном итоге будет действовать так же, как "s/fox.*[0-9]\{4\}//" (ваша исходная команда с не вносящими вклад символами удалены); то есть это изменится

Быстрая коричневая лиса прыгает в 2012 и 2013 годах.

в

Быстрый бурый лис прыгает в 2012 году #### и 2013 ####.

а затем

Быстрый коричневый.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .