Разбор параметра из строки | регулярное выражение | Переполнение стека

У меня проблемы с анализом параметра из строки.

Параметр определяется следующим:

  • может быть написано в короткой или длинной записи, p.ex:
    / —долго

  • символы варьируются от [a-z0-9] для коротких и [a-z0-9 \ -] для длинных обозначений, p.ex:
    —давно с тиром

  • может иметь значение, но не обязательно, p.ex:
    -тест / —аааа

  • может иметь несколько аргументов, без кавычек, p.ex:
    -val1 val2
    (это должно быть записано как одна группа: value = «val1 val2»)

  • может иметь собственный текст внутри кавычек
    —Кастом «здесь может выдержать все, —test test :(«

  • Параметр может иметь «!» спереди
    ! —тестовый тест / ! —

  • значения могут иметь «-» внутри
    -значение с тире

Все эти параметры входят в одну длинную строку, p.ex:

-a val1 ! -b val2 --other "string with crazy -a --test stuff inside" --param-with-dash val1 val2 -test value-with-dash ! -c -d ! --test

РЕДАКТИРОВАТЬ —-

также --param value-with-dash

КОНЕЦ РЕДАКТИРОВАНИЯ

Это настолько близко, насколько я могу получить:

https://regex101.com/r/3aPHzp/1

/(?:(?P<inverted>\!) )?(?P<names>\-{1,2}\S+)($| (?P<values>.+(?=(?: [\!|\-])|$)))/U

к сожалению, он ломается, когда дело доходит до значения свободного текста внутри кавычек. И когда за параметром без значения следует следующий параметр.

(Я пытаюсь проанализировать вывод iptables-save, если вы заинтересовались. Кроме того, возможно, что я разбил, может раньше разбить строку другим причудливым способом, чтобы избежать регулярного выражения Хью, но я его не вижу).

Большое спасибо за Вашу помощь!

— ОКОНЧАТЕЛЬНОЕ РЕШЕНИЕ —

для PHP> = 5.6

(?<inverted>!)?\s*(?<name>--?\w[\w-]*)\s*(?<values>(?:\s*(?:\w\S*|["'](?:[^"'\\]*(?:\\.[^"'\\]*)*)['"]))*)\K

Демо-версия: https://regex101.com/r/xSfgxP/1

для PHP < 5,6

(?<inverted>\!)?\s*(?<=(?:\s)|^)(?<name>\-{1,2}\w[\w\-]*)\s+(?<value>(?:\s*(?:\w\S*|["'](?:[^"'\\]*(?:\\.[^"'\\]*)*)['"]))*)

1

Решение

RegEx:

(?<inverted>!)?\s*(?<name>--?\w[\w-]*)\s*(?<values>(?:\s*(?:\w\S+|["'](?:[^"'\\]*(?:\\.[^"'\\]*)*)['"]))*)\K

Живая демо (Обновлено)

Сломать

 (?<inverted> ! )?             # (1) Named-capturing group for inverted result
\s*                           # Match any spaces
(?<name> --? \w [\w-]* )      # (2) Named-capturing group for parameter name
\s*                           # Match any spaces
(?<values>                    # (3 start) Named capturing group for values
(?:                           # Beginning of a non-capturing group (a)
\s*                      # Match any spaces
(?:                      # Beginning of a non-capturing group (b)
\w\S+                   # Match a [a-zA-Z0-9_] character then any non-whitespace characters
|                          # Or
["']                    # Match a qoutation mark
(?:                     # Beginning of a non-capturing group (c)
[^"'\\]*               # Match anything except `"`, `'` or `\`
(?: \\ . [^"'\\]* )*   # Match an escaped character then anyhthing except `"`, `'` or `\` as much as possible
)                       # End of non-capturing group (c)
['"]                    # Match qutation pair
)                        # End of non-capturing group (b)
)*                            # Greedy (a), end of non-capturing group (a)
)                             # (3 end)
\K                            # Reset allocated memory of all previously matched characters

Код PHP:

<?php

$str = '-a val1 ! -b val2 --custom "string :)(#with crazy -a --test stuff inside" --param-with-dash val1 val2 -c ! -d ! --test';
$re = <<< 'RE'
~(?<inverted>!)?\s*(?<name>--?\w[\w-]*)\s*(?<values>(?:\s*(?:\w\S+|["'](?:[^"'\\]*(?:\\.[^"'\\]*)*)['"]))*)\K~
RE;

preg_match_all($re, $str, $matches, PREG_SET_ORDER);
print_r(array_map('array_filter', $matches));

Выход:

Array
(
[0] => Array
(
[name] => -a
[2] => -a
[values] => val1
[3] => val1
)

[1] => Array
(
[inverted] => !
[1] => !
[name] => -b
[2] => -b
[values] => val2
[3] => val2
)

[2] => Array
(
[name] => --custom
[2] => --custom
[values] => "string :)(#with crazy -a --test stuff inside"[3] => "string :)(#with crazy -a --test stuff inside")

[3] => Array
(
[name] => --param-with-dash
[2] => --param-with-dash
[values] => val1 val2
[3] => val1 val2
)

[4] => Array
(
[name] => -c
[2] => -c
)

[5] => Array
(
[inverted] => !
[1] => !
[name] => -d
[2] => -d
)

[6] => Array
(
[inverted] => !
[1] => !
[name] => --test
[2] => --test
)

)
0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]