Учитывая вход как
${first_name}, ${last_name}, ${create_date:(Y-m-d)}, ${submit_date:(Y-m-d)}
я могу использовать \${(.*)}
чтобы захватить все в скобках. Когда суффикс появляется как на датах в примере, я хочу зафиксировать его как свою собственную группу. Как я могу сделать это с одним регулярным выражением?
Вы можете попробовать это,
\$\{([^:, ]*(?::\(([^)]*)\))?)\}
демонстрация,,, в котором общее значение (строка) внутри фигурной скобки фиксируется в group 1
и необязательное значение (строка) фиксируется в group 2
,
и вы можете попробовать это тоже, если вы не хотите инклюзивного отношения между группой 1 и 2,
\$\{([^:, ]*)(?::\(([^)]*)\))?\}
Я думаю, что ваш оригинальный подход \${(.*)}
имеет небольшую проблему, которая заключается в том, что ваш шаблон сопоставления .*
включает в себя }
символ, которому вы не хотите соответствовать. Фактически, как только вы начинаете захват, это единственное, что вы не хотите сопоставлять, поэтому мы изменим:
.* // match anything zero or more times
в
[^}]* // match anything that isn't } zero or more times
Но вы хотите сопоставить все в фигурных скобках, если у него нет структуры some_underscored_words:(desired-text)
в этом случае вы хотите соответствовать desired-text
,
Я бы решил это, используя ?
оператор, который вы помещаете после группы захвата, чтобы определить его как необязательный. ?
является жадным, что означает, что он сначала попытается сопоставить, и только в случае неудачи он попытается обработать совпадения без дополнительного шаблона.
Чтобы думать об этом, полезно перефразировать то, что вы хотите, используя жадное мышление.
Вместо того чтобы говорить:
Я хочу захватить все, что находится внутри фигурных скобок, а также
захватить значение в скобках, если они существуют
Измените это на:
Я хочу захватить значение, которое вложено в скобках
внутри фигурных скобок, но если этого не существует, я просто буду
что бы ни было внутри брекетов.
Превратив это в регулярное выражение, я получаю это:
\${([a-z_]+:\()?([^\)}]*)
Разбивая это:
Начните с поиска уникального символа:
${
Попробуйте сопоставить с вложенным шаблоном:
([a-z_]+:\()?
Это соответствует any_underscored_lowercase_words
один или несколько раз (+
) с последующим :(
Теперь мы сопоставляем ноль или более букв, которые не являются ни одним из наших закрывающих тегов. )
или же }
([^\)}]*)
Будучи жадным, он идет прямо к вложенному шаблону. В противном случае совпадение сводится к захвату всего, что не является ни одним из закрывающих символов.
Один сценарий, который я могу придумать, где это не сработает, это:
${seems like a normal match) wait where did these letters go?}
Что даст вам «похоже на нормальный матч».
Чтобы построить лучший / самый быстрый шаблон, вы должны позволить механизму регулярных выражений работать как можно более жадным образом, что означает использование таких квантификаторов, как *
а также +
без запаздывания ?
,
Следующий шаблон потребует первую группу захвата (выходной столбец [1]
) и сделать вторую группу захвата необязательной (выходной столбец) [2]
).
Предлагаемая модель: ~\$\{([^:}]+)(?::([^}]+))?~
(Образец Демо)
~ #starting pattern delimiter
\$\{ #match a dollar sign then opening curly bracket
( #start Capture Group #1
[^:}]+ #match one or more non-colon, non-closing curly bracket characters
) #end Capture Group #1
(?: #start non-capturing group
: #match a colon
( #start Capture Group #2
[^}]+ #match one or more non-closing curly brackets
) #end Capture Group #2
)? #end non-capturing group and allow zero or one occurence of the group
~ #end pattern delimiter
Код: (демонстрация)
$string = '${first_name}, ${last_name}, ${create_date:(Y-m-d)}, ${submit_date:(Y-m-d)}';
var_export(preg_match_all('~\$\{([^:}]+)(?::([^}]+))?~', $string, $out, PREG_SET_ORDER) ? $out : 'fail');
Вы можете игнорировать [0]
(полная строка) совпадение столбца. Вас интересуют только первая и вторая группы захвата.
Выход:
array (
0 =>
array (
0 => '${first_name',
1 => 'first_name',
),
1 =>
array (
0 => '${last_name',
1 => 'last_name',
),
2 =>
array (
0 => '${create_date:(Y-m-d)',
1 => 'create_date',
2 => '(Y-m-d)',
),
3 =>
array (
0 => '${submit_date:(Y-m-d)',
1 => 'submit_date',
2 => '(Y-m-d)',
),
)