sed: видалення тексту між рядком до першого появи іншого рядка


4

Уявіть, у мене є щось на кшталт наступного тексту:

Швидка бура лиса стрибає у 2012 та 2013 роках

І я хотів би видалити частину з "лисиці", включаючи чотири номери, але тільки в першому випадку, тому я закінчую:

Швидкий коричневий і 2013 рік

Щось подібне ...

відлуння "Швидка бура лиса стрибає у 2012 та 2013 роках" \
   | sed "s / fox. * \ ([0-9] \ {4 \} \) // g"

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

Швидкий коричневий

Тож було видалено все, включаючи останнє виникнення чотирьох чисел.

Якісь ідеї?


Стандартні квантори в регулярних виразах жадібні, тобто вони відповідають максимальній кількості.
kinokijuf

Відповіді:


6

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

Що потрібно, можна досягти в Perl, використовуючи ?не жадібний квантор:

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

Ви також можете видалити додатковий простір.


Чорт забирай, outninja'd. Що це стосується додаткового простору? (+1)
grawity

@grawity: Спробуйте додати пробіл після правої дужки.
choroba

Чи корисні дужки?
Скотт

@Scott: Не дуже в цьому випадку :-)
choroba

1

Якщо припустити, що ви хочете використовувати лише sed, і ви хочете, щоб кінець матчу був першою групою цифр, не піклуючись про те, що слово після цифр, це працює:

відлуння "Швидка бура лиса стрибає у 2012 та 2013 роках" \
   | sed "s / fox [^ 0-9] [^ 0-9] * [0-9] [0-9] * //"

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

відлуння "Швидка бура лиса стрибає у 2012 та 2013 роках" \
   | sed "s / fox [^ 0-9] * \ ([0-9] \ {4 \} \) //"

1

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

відлуння "Швидка бура лиса стрибає над 42 ледачими собаками у 2012 та 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.

Щоб також видалити один пробіл після номера, якщо такий є,

відлуння "Швидка бура лиса стрибає над 42 ледачими собаками у 2012 та 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 ####.

а потім до

Швидкий коричневий.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.