Как я могу использовать присмотр за одинарной или двойной кавычкой? - PullRequest
1 голос
/ 04 апреля 2019

У меня есть ряд строк, которые я хочу извлечь:

hello.this_is("bla bla bla")
some random text
hello.this_is('hello hello')
other stuff

Что мне нужно получить (из многих файлов, но здесь это не важно), это содержимое между hello.this_is( и ), поэтому мой желаемый вывод:

bla bla bla
hello hello

Как видите, текст в скобках может быть заключен в двойные или одинарные кавычки.

Если бы это были только одинарные кавычки, я бы использовалоглянуться назад и заглянуть в будущее так:

grep -Po "(?<=hello.this_is\(').*(?=')" file
#                            ^      ^
# returns ---> hello hello

Аналогично, чтобы получить строки из двойных кавычек, я бы сказал:

grep -Po '(?<=hello.this_is\(").*(?=")' file
#                            ^      ^
# returns ---> bla bla bla

Однако я хочу сопоставить оба случая, поэтомуон получает как одинарные, так и двойные кавычки.Я попытался использовать $'' для выхода, но не смог заставить его работать:

grep -Po '(?<=hello.this_is\($'["\']').*(?=$'["\']')' file
#                            ^^^^^^^^      ^^^^^^^^

Я, конечно, могу использовать номер ASCII и сказать:

grep -Po '(?<=hello.this_is\([\047\042]).*' file

, но я бы хотелиспользовать кавычки и одинарные кавычки, так как 047 и 042 не так характерны для меня, как одинарные и двойные кавычки.

Ответы [ 3 ]

1 голос
/ 04 апреля 2019

Примечание. Команда sed в нижней части этого ответа работает только в том случае, если ваши строки имеют строки с хорошим поведением, такие как

"foo"

или

'bar'

Как тольковаши строки начинают плохо себя вести :) как:

"hello \"world\""

больше не будет работать.

Ваш ввод выглядит как исходный код.Для стабильного решения я рекомендую использовать синтаксический анализатор для этого языка для извлечения строк.


Для тривиальных вариантов использования:

Вы можете использовать sed.Предполагается, что решение будет работать на любой платформе POSIX в отличие от grep -oP, которая работает только с GNU grep:

sed -n 's/hello\.this_is(\(["'\'']\)\([^"]*\)\(["'\'']\).*/\2/gp' file
#                                    ^^^^^^^^              ^^
#                                          capture group 2 ^
1 голос
/ 04 апреля 2019

Используйте группу захвата и ищите ее содержимое следующим образом:

grep -Po 'hello\.this_is\(([\047"])((?!\1).|\\.)*\1\)' file

Это касается и экранированных символов, например, hello.this_is("bla b\"la bla")

См. живая демонстрация здесь

Если выходные данные должны заключаться в скобки, используйте \K и положительный прогноз:

grep -Po 'hello\.this_is\(([\047"])\K((?!\1).|\\.)*(?=\1\))' file

Выходы:

bla bla bla
hello hello
0 голосов
/ 04 апреля 2019

Основываясь на отличных ответах revo и hek2mgl, я использовал grep, например:

grep -Po '(?<=hello\.this_is\((["'\''])).*(?=\1)' file

Что можно объяснить следующим образом:

  • grep
  • -Po использует машину регулярных выражений Perl и просто печатает совпадения
  • '(?<=hello\.this_is\((["'\''])).*(?=\1)' выражение
    • (?<=hello\.this_is\((["'\''])) поиск: строки поиска, начинающиеся с "hello.this_is ("затем следует либо ' или ". Также захватите этот последний символ, который будет использоваться позже.
    • .* соответствует всему ...
    • (?=\1) до захваченного символа(то есть, ' или ") появляется снова.

Ключом здесь было использование ["'\''] для обозначения либо ', либо "Делая '\'', мы закрываем вмещающее выражение, заполняем его литералом ' (который мы должны экранировать) и снова открываем вмещающее выражение.

...