Синтаксический анализ многострочного ini-подобного файла с использованием регулярного выражения PCRE

#php #regex #pcre

#php #регулярное выражение #pcre

Вопрос:

У меня есть ini-подобный файл, в котором у нас есть список <key> = <value> элементов. Что усложняет ситуацию, так это то, что некоторые значения являются многострочными и могут содержать = символы (закрытый ключ tls). Пример:

 groupid = foo
location = westus
randomkey = fbae3700c34cb06c
resourcename = example4-resourcegroup
tls_private_key = -----BEGIN RSA PRIVATE KEY-----
//stuff
-----END RSA PRIVATE KEY-----

foo = 123
faa = 223
 

До сих пор у меня был такой шаблон /^(.*?) = (.*[^=]*)$/m , и он работает для всех ключей, кроме tls_private_key, потому что он содержит = so, поэтому он извлекает только частичное значение.

Есть предложения?

Ответ №1:

Вы можете сопоставить все значения по нескольким строкам, утверждая, что следующая строка не содержит пробела со знаком равенства:

 ^(.*?) = (.*(?:R(?!.*? = ).*)*)
 

Демонстрация регулярных выражений

Если в ключе не может быть пробелов:

 ^([^s=] )h =h (.*(?:R(?![^s=] h =h ).*)*)$
 

Объяснение

  • ^ Начало строки
  • ([^s=] ) Захватите группу 1, сопоставьте 1 символы, отличные от = или пробельный символ
  • h =h Сопоставьте = пробелы между
  • ( Группа захвата 2
    • .* Сопоставьте всю строку
    • (?:R(?![^s=] h =h ).*)* Повторите все следующие строки, которые не содержат пробел = пробел
  • ) Закрыть группу захвата 2
  • $ Конец строки

Демонстрация регулярных выражений

Ответ №2:

Вы можете использовать это регулярное выражение с предвидением:

 ^h*(?<key>[w-] )h*=h*(?<value>[sS]*?)(?=Rh*[w-] h*=|z)
 

Демонстрация регулярных выражений

Подробности регулярных выражений:

  • ^ Запустите строку
  • h* : 0 или более горизонтальных пробелов
  • (?<key>[w-] ) : Группа key , которая соответствует символам 1 word или дефисам
  • h* : 0 или более горизонтальных пробелов
  • = : Сопоставить =
  • h* : 0 или более горизонтальных пробелов
  • (?<value>[sS]*?) : Группа value , которая соответствует 0 или более любых символов, включая новые строки
  • (?=Rh*[w-] h*=|z) : Посмотрите вперед, чтобы утверждать, что в следующей позиции у нас есть разрыв строки, за которым следует ключ, и = или есть конец ввода

Ответ №3:

Еще один вариант:

 (?sm)^([^=n]*)s=s(.*?)(?=n[^=n]*s=s|z)
 

Смотрите доказательство

Объяснение

 --------------------------------------------------------------------------------
  (?ms)                    set flags for this block (with ^ and $
                           matching start and end of line) (with .
                           matching n) (case-sensitive) (matching
                           whitespace and # normally)
--------------------------------------------------------------------------------
  ^                        the beginning of a "line"
--------------------------------------------------------------------------------
  (                        group and capture to 1:
--------------------------------------------------------------------------------
    [^=n]*                  any character except: '=', 'n'
                             (newline) (0 or more times (matching the
                             most amount possible))
--------------------------------------------------------------------------------
  )                        end of 1
--------------------------------------------------------------------------------
  s                       whitespace (n, r, t, f, and " ")
--------------------------------------------------------------------------------
  =                        '='
--------------------------------------------------------------------------------
  s                       whitespace (n, r, t, f, and " ")
--------------------------------------------------------------------------------
  (                        group and capture to 2:
--------------------------------------------------------------------------------
    .*?                      any character (0 or more times (matching
                             the least amount possible))
--------------------------------------------------------------------------------
  )                        end of 2
--------------------------------------------------------------------------------
  (?=                      look ahead to see if there is:
--------------------------------------------------------------------------------
    n                       'n' (newline)
--------------------------------------------------------------------------------
    [^=n]*                  any character except: '=', 'n'
                             (newline) (0 or more times (matching the
                             most amount possible))
--------------------------------------------------------------------------------
    s                       whitespace (n, r, t, f, and " ")
--------------------------------------------------------------------------------
    =                        '='
--------------------------------------------------------------------------------
    s                       whitespace (n, r, t, f, and " ")
--------------------------------------------------------------------------------
   |                        OR
--------------------------------------------------------------------------------
    z                       the end of the string
--------------------------------------------------------------------------------
  )                        end of look-ahead