Как игнорировать экранированные скобки в регулярном выражении - PullRequest
0 голосов
/ 09 марта 2019

Я пытаюсь извлечь некоторые пользовательские свойства из PDF с помощью регулярных выражений (я буду использовать grep).

Пользовательские свойства PDF - это значение ключа, сохраненное в этом формате:

<</key1(value1)/key2(value2)/key3(value3)>>

Скобки внутри значений экранированы:

/key4(outside \(inside\) outside)

Я сделал следующее регулярное выражение для извлечения значения ключа:

grep -Po '(?<=key4\().*?(?=\))' "sample.txt"

Однако при применении его к ключу 4 (с круглыми скобками) оноприводит к:

outside \(inside\

Потому что он останавливается в первом ) (в том, который сбежал), а не в неотбегшем.

Как я могу игнорировать в своем регулярном выраженииэкранированные скобки?

Заранее спасибо.

PD: Я открыт для предложений в sed или awk.

Ответы [ 3 ]

1 голос
/ 09 марта 2019

Вы можете использовать sed решение типа

sed 's/.*key4(\([^\()]*\(\\.[^\()]*\)*\)).*/\1/'
sed -E 's/.*key4\(([^\()]*(\\.[^\()]*)*)\).*/\1/'

См. онлайн sed демо .

Детали шаблона POSIX ERE

  • .* - любые 0+ символов
  • key4\( - key( буквенная строка
  • \( - a (`char
  • ([^\()]*(\\.[^\()]*)*) - Группа 1:
    • [^\()]* - 0 или более символов, отличных от \, ( и )
    • (\\.[^\()]*)* - 0 или более повторений
      • \\. - \, за которым следует 1 символ
      • [^\()]* - 0 или более символов, отличных от \, ( и )
  • \) - ) char
  • .* - любые 0+ символов

Обратите внимание, что в шаблоне POSIX BRE только литеральные и захватывающие скобки, выходящие за пределы подкачки (( в POSIX BRE соответствует буквенному символу (, это не начало группы захвата).

\1 в заменяющей части является заполнителем группы 1 и заменяет все совпадение значением этой группы.

1 голос
/ 09 марта 2019

Вы можете сделать это следующим образом:

(?<=key4\()[^\\()]*(?:\\[\S\s][^\\()]*)*(?=\))

https://regex101.com/r/B4qKdh/1

Расширен:

 (?<= key4\( )
 [^\\()]* 
 (?: \\ [\S\s] [^\\()]* )*
 (?= \) )
0 голосов
/ 10 марта 2019

С любым awk в любой оболочке на любой коробке UNIX:

$ awk '
    { gsub(/\\[(]/,"\n1"); gsub(/\\)/,"\n2") }
    match($0,/[/]key4[(][^)]+/) {
        $0 = substr($0,RSTART+6,RLENGTH-6)
        gsub(/\n1/,"\\("); gsub(/\n2/,"\\)")
        print
    }
' file
outside \(inside\) outside

С GNU awk для сопоставления 3-го аргумента ():

$ awk '
    { gsub(/\\[(]/,"\n1"); gsub(/\\)/,"\n2") }
    match($0,/[/]key4[(]([^)]+)/,a) {
        $0 = a[1]
        gsub(/\n1/,"\\("); gsub(/\n2/,"\\)")
        print
    }
' file
outside \(inside\) outside

Выше просто замените \( и \) строками, которые содержат символы новой строки (которые не могут существовать с записями, разделенными символами новой строки) \n1 и \n2, затем найдет совпадение для key4, затем вернет замещающие строки в их исходные значения перед печатью.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...