Як витягти текст із рядка за допомогою sed?


95

Мій приклад рядка такий:

This is 02G05 a test string 20-Jul-2012

Тепер із наведеного рядка я хочу витягти 02G05. Для цього я спробував наступний регулярний вираз із sed

$ echo "This is 02G05 a test string 20-Jul-2012" | sed -n '/\d+G\d+/p'

Але вищевказана команда нічого не друкує, і я вважаю, що вона не може зрівняти нічого з шаблоном, який я надав sed.

Отже, моє питання полягає в тому, що я тут роблю не так і як це виправити.

Коли я пробую наведені вище рядки та шаблони за допомогою python, я отримую свій результат

>>> re.findall(r'\d+G\d+',st)
['02G05']
>>>

6
Python точно не є sed. Їх смакові рецепти досить різні.
тричі

Відповіді:


91

Можливо \d, ваш шаблон не підтримує шаблон sed. Спробуйте [0-9]або [[:digit:]]замість цього.

Щоб надрукувати лише фактичну відповідність (а не весь відповідний рядок), використовуйте заміну.

sed -n 's/.*\([0-9][0-9]*G[0-9][0-9]*\).*/\1/p'

6
Дякую, це спрацювало нормально. Але у мене виникає запитання, чому .*це потрібно з вашим регулярним виразом, тому що при спробі sed -n 's/\([0-9]\+G[0-9]\+\)/\1/p'він просто друкує весь рядок.
RanRag

7
Ось чому, чи не так? Замініть усе, що надходить до і після матчу, норшинг, а потім надрукуйте весь рядок.
триплі

1
@tripleee Це лише 2G05не друкує 02G05. Працює вираз's/.*\([0-9][0-9]G[0-9][0-9]*\).*/\1/p'
Kshitiz Sharma

1
Це жорстко кодує його рівно до двох цифр. Щось подібне sed -n 's/\(.*[^0-9]\)\?\([0-9][0-9]*G[0-9][0-9]*\).*/\2/p'було б більш загальним. (Я припускаю, що ваша sedпідтримка не буде \?нульовим або одним випадком.)
tripleee

Дивіться також stackoverflow.com/a/48898886/874188 про те , як замінити різні інші загальні Perl вислизає , як \w, \sі т.д.
tripleee

99

Як щодо використання grep -E?

echo "This is 02G05 a test string 20-Jul-2012" | grep -Eo '[0-9]+G[0-9]+'

3
+1 Це простіше, і воно також буде правильно обробляти випадки декількох збігів на одному рядку. Для sedцього випадку можна розробити складний сценарій, але навіщо турбуватися?
триплеє

egrepвикористовує розширений регулярний вираз sedі grepвикористовує стандартний регулярний вираз, egrepабо grep -eабо sed -Eвикористовує розширений регулярний вираз, а код python у питанні використовує PCRE, (загальний регулярний вираз perl) GNU grep може використовувати PCRE з -Pопцією.
Феліпе Буччоні

@FelipeBuccioni насправді це повинно бути egrepабо grep -Eабоsed -r
SensorSmith

Для одного (першого) збігу додайте `| head -1` (без зворотних позначок), відповідно до цієї відповіді на інше питання.
SensorSmith

1
grepповинен -m 1зупинитися після першого матчу.
триплі

5

sedне розпізнає \d, використовуйте [[:digit:]]замість цього. Вам також потрібно буде вийти з режиму +або скористатися -rперемикачем (-E на OS X).

Зауважте, що це [0-9]працює також для арабсько-індуїстських цифр.


Я спробував sed -n '/[0-9]\+G[0-9]\+/p'. Тепер він просто друкує цілий рядок
RanRag


5

Спробуйте замість цього:

echo "This is 02G05 a test string 20-Jul-2012" | sed 's/.* \([0-9]\+G[0-9]\+\) .*/\1/'

Але зверніть увагу, якщо на одному рядку є два шаблони, друкується 2-й.


Або загальніше останній, якщо є кілька збігів.
триплі

0

Спробуйте використовувати рекстракцію . Це дозволить вам витягти текст за допомогою регулярного виразу та переформатувати його.

Приклад:

$ echo "This is 02G05 a test string 20-Jul-2012" | ./rextract '([\d]+G[\d]+)' '${1}'

2G05

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