Как извлечь текст из строки с помощью sed?

98

Моя примерная строка выглядит следующим образом:

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']
>>>
RanRag
источник
6
Python определенно нет sed. Их ароматы регулярных выражений совершенно разные.
Tripleee

Ответы:

96

Возможно, шаблон \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
Вот почему, не так ли? Замените все, что идет до и после совпадения, на norhing, затем распечатайте всю строку.
tripleee
1
@tripleee Это только 2G05не печатает 02G05. Выражение, которое работает's/.*\([0-9][0-9]G[0-9][0-9]*\).*/\1/p'
Кшитиз Шарма
1
Это жестко кодирует его ровно до двух цифр. Что-то вроде sed -n 's/\(.*[^0-9]\)\?\([0-9][0-9]*G[0-9][0-9]*\).*/\2/p'бы более общего. (Я предполагаю, что вы sedподдерживаете \?ноль или один случай.)
tripleee
См. Также stackoverflow.com/a/48898886/874188, чтобы узнать, как заменить различные другие распространенные \w\s
escape-
102

Как насчет использования grep -E?

echo "This is 02G05 a test string 20-Jul-2012" | grep -Eo '[0-9]+G[0-9]+'
мВч
источник
3
+1 Это проще, а также будет правильно обрабатывать случай нескольких совпадений в одной строке. Для sedэтого случая можно было бы разработать сложный сценарий, но зачем?
tripleee
egrepиспользует расширенное регулярное выражение sedи grepиспользует стандартное регулярное выражение egrepили grep -eили sed -Eиспользует расширенное регулярное выражение, а код python в вопросе использует PCRE (общее регулярное выражение perl) GNU grep может использовать PCRE с -Pопцией.
Фелипе Буччони,
@FelipeBuccioni на самом деле это должно быть egrepили grep -Eилиsed -r
SensorSmith
Для единственного (первого) совпадения добавьте `| голова -1` (без обратных кавычек), согласно этому ответу на другой вопрос.
SensorSmith
1
grepдолжен -m 1остановиться после первого матча.
tripleee
5

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

Обратите внимание, что [0-9]это также работает с арабско-индуистскими цифрами.

Приостановлено до дальнейшего уведомления.
источник
Я пробовал sed -n '/[0-9]\+G[0-9]\+/p'. Теперь он просто печатает всю строку
RanRag
@Noob: вам нужно будет использовать замену, чтобы исключить части, которые вы не хотите печатать .
Приостановлено до дальнейшего уведомления.
5

Попробуйте вместо этого:

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

Но обратите внимание: если в одной строке есть два шаблона, будет напечатан второй.

Жолт Ботыкай
источник
Или, в более общем смысле, последний, если есть несколько совпадений.
Tripleee
0

Попробуйте использовать rextract . Это позволит вам извлекать текст с помощью регулярного выражения и переформатировать его.

Пример:

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

2G05
Тим Саванна
источник
Если здесь используется стандартное регулярное выражение, квадратные скобки \dсовершенно излишни.
tripleee