Як зробити негнійний сірник у грепі?


Відповіді:


276

Ви шукаєте не жадібну (або ліниву) відповідність. Щоб отримати не жадібну відповідність у регулярних виразах, вам потрібно використовувати модифікатор ?після кількісного показника. Наприклад, ви можете змінити .*на .*?.

За замовчуванням grepне підтримує не жадібних модифікаторів, але ви можете використовувати grep -Pсинтаксис Perl.


3
eegg: крапка всіх модифікаторів також відома як багатолінійна. Це модифікатор, який змінює "." відповідати поведінці, щоб включати нові рядки (зазвичай це не так). У grep немає такого модифікатора, але є у pcregrep .
А. Вілсон

1
Корекція: у більшості ароматів регулярного вираження, які підтримують його, режим, що дозволяє .відповідати новим рядкам, називається DOTALL або однорядковий режим; Рубі - це єдиний, хто називає це багаторядковим . В інших ароматах багатолінійний режим - це режим, який дозволяє якорям ( ^і $) збігатися на межі лінії. У Ruby немає еквівалентного режиму, оскільки в Ruby вони завжди працюють так.
Алан Мур

5
-Pбула абсолютно новою для мене, я щасливо поздоровився роками, і лише використовую -E... стільки даремно витрачених років! - Примітка до самоврядування: перечитайте сторінки Man як (навіть більше!) Звичайну річ, ви ніколи не перетравлюєте достатню кількість перемикачів та параметрів.
ocodo

29
На деяких платформах (наприклад, Mac OS X) grepне підтримується -P, але якщо ви використовуєте, egrepви можете використовувати .*?шаблон для досягнення того ж результату. egrep -o 'start.*?end' text.html
SaltyNuts

4
Як розширення до коментаря @SaltyNuts, Mac OS X не підтримує, -Pале зате -Eзакликає, egrepотже, запропоноване .*?працює просто чудово.
Фредрік Ерландссон

83

Насправді .*?єдині роботи в Росії perl. Я не впевнений, яким би був еквівалентний синтаксис розширеного regexp grep. На щастя, ви можете використовувати синтаксис perl з grep, щоб grep -Pце спрацювало, але grep -Eце те саме, egrepщо не було б (було б жадібно).

Дивіться також: http://blog.vinceliu.com/2008/02/non-greedy-regular-expression-matching.html


9
grep -Pне працює в GNU grep 2.9 - просто спробував це (він не помиляється, просто мовчки не застосовує ?. Інтертестно також не клас, наприклад:env|grep '[^\=]*\='
Roberto tomás

2
У Дарвіні / OS X 10.8 Mountain Lion немає grep -Pваріантів чи pgrepкоманд, але це egrepчудово.
Стів HHH

2
На pgrepмоєму вікні OS X 10.9 є команда, але це зовсім інша програма, мета якої - "пошук або подання сигналів процесів по імені".
Desty

@ robertotomás Відповідаючи на 6-річний коментар тут, але .... Я теж подумав це, а потім зрозумів, що отримую кілька не жадібних матчів. Наприклад, на кольоровому терміналі ви бачите, що `echo" bbbbb "| grep -P 'b. *? b'` повертає 2 матчі.
zzxyz

12

Мій греп, який працює після випробування матеріалів у цій темі:

echo "hi how are you " | grep -shoP ".*? "

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

(Моя була рядок за рядком пошуку, щоб виплюнути слова)


3
-shoPприємний мнемонік :)
Маріуш

echo "bbbbb" | grep -shoP 'b.*?b'це трохи досвіду навчання. Єдине, що працювало для мене і з точки зору явно лінивого.
zzxyz

12

grep

Для не жадібного матчу grepви можете використовувати заперечений клас персонажів. Іншими словами, намагайтеся уникати макіяжів.

Наприклад, щоб отримати всі посилання на файли jpeg із вмісту сторінки, ви використовуєте:

grep -o '"[^" ]\+.jpg"'

Щоб мати справу з декількома лініями, xargsспочатку подайте вхід . Для продуктивності використовуйте ripgrep.


3

Коротка відповідь використовує наступний регулярний вираз:

(?s)<car .*? model=BMW .*?>.*?</car>
  • (? s) - це поєднує міжрядкові лінії
  • . *? - відповідає будь-якому персонажу, декілька разів ледачим чином (мінімальна відповідність)

(Трохи) більш складна відповідь:

(?s)<([a-z\-_0-9]+?) .*? model=BMW .*?>.*?</\1>

Це дозволить співставити car1 та car2 у наступному тексті

<car1 ... model=BMW ...>
...
...
...
</car1>
<car2 ... model=BMW ...>
...
...
...
</car2>
  • (..) являє собою групу захоплення
  • \ 1 у цьому контексті збігається з тим самим текстом, що останній раз узгоджується із захопленням групи №1

1

Вибачте, що я запізнююсь на 9 років, але це може допомогти глядачам у 2020 році.

Отже, припустимо, у вас є така лінія "Hello my name is Jello". Тепер ви хочете знайти слова, які починаються з 'H'і закінчуються 'o', з будь-якою кількістю символів між ними. І ми не хочемо рядків, ми просто хочемо слова. Тож для цього ми можемо використовувати вираз:

grep "H[^ ]*o" file

Це поверне всі слова. Це працює так: Це дозволить усім символам замість символів пробілу посередині, таким чином ми зможемо уникнути кількох слів в одному рядку.

Тепер ви можете замінити пробільний символ будь-яким іншим символом, який ви хочете. Припустимо, початковий рядок був "Hello-my-name-is-Jello", тоді ви можете отримати слова, використовуючи вираз:

grep "H[^-]*o" file

0

Я знаю, що це трохи мертвий пост, але я просто помітив, що це працює. Це видалило і очищення, і очищення з мого результату.

> grep -v -e 'clean\-\?up'
> grep --version grep (GNU grep) 2.20
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.