Регулярное выражение для разбора данных, разделенных каналом, заключенных в двойные скобки - PullRequest
2 голосов
/ 25 августа 2009

Я пытаюсь найти такую ​​строку:

{{name|arg1|arg2|...|argX}}

с регулярным выражением

Я использую preg_match с

/{{(\w+)\|(\w+)(?:\|(.+))*}}/

но я получаю нечто подобное, когда использую более двух аргументов

Array
(
    [0] => {{name|arg1|arg2|arg3|arg4}}
    [1] => name
    [2] => arg1
    [3] => arg2|arg3|arg4
)

Первые два элемента не могут содержать пробелы, остальные могут. Возможно, я слишком долго над этим работаю, но не могу найти ошибку - любая помощь будет принята с благодарностью.

Спасибо, Ян

Ответы [ 5 ]

4 голосов
/ 25 августа 2009

Не используйте регулярные выражения для подобных простых задач. Что вам действительно нужно:

$inner = substr($string, 2, -2);
$parts = explode('|', $inner);

# And if you want to make sure the string has opening/closing braces:
$length = strlen($string);
assert($inner[0] === '{');
assert($inner[1] === '{');
assert($inner[$length - 1] === '}');
assert($inner[$length - 2] === '}');
3 голосов
/ 25 августа 2009

Проблема здесь: \ | (. +)

Регулярные выражения по умолчанию соответствуют максимально возможному количеству символов. Поскольку . это любой символ, другие экземпляры | тоже счастливы, что не то, что вы хотели бы.

Чтобы предотвратить это, вы должны исключить | из выражения, говорящего «сопоставить все, кроме |», что приводит к \ | ([^ \ |] +).

0 голосов
/ 25 августа 2009

действительно, это из инструкции PCRE:

Когда подшаблон захвата повторяется, полученное значение является подстрока, которая соответствует финалу итерация. Например, после (tweedle [dume] {3} \ s *) + соответствует «Твидлум Твидледи» значение захваченная подстрока «Труляля». Однако, если есть вложенные субпаттерны захвата, соответствующие захваченные значения могут иметь был установлен в предыдущих итерациях. За Например, после / (a ​​| (b)) + / совпадений «аба» значение второго захваченного подстрока "b".

0 голосов
/ 25 августа 2009

Конечно, вы получите что-то подобное :) В регулярном выражении нет способа вернуть динамическое количество совпадений - в вашем случае аргументы.

Глядя на то, что вы хотите сделать, вы должны идти в ногу с текущим регулярным выражением и просто взорвать дополнительные аргументы с помощью '|' и добавьте их в массив args.

0 голосов
/ 25 августа 2009

Должно работать от 1 до N аргументов

<code><?php

$pattern = "/^\{\{([a-z]+)(?:\}\}$|(?:\|([a-z]+))(?:\|([a-z ]+))*\}\}$)/i";

$tests = array(
    "{{name}}"                          // should pass
  , "{{name|argOne}}"                   // should pass
  , "{{name|argOne|arg Two}}"           // should pass
  , "{{name|argOne|arg Two|arg Three}}" // should pass
  , "{{na me}}"                         // should fail
  , "{{name|arg One}}"                  // should fail
  , "{{name|arg One|arg Two}}"          // should fail
  , "{{name|argOne|arg Two|arg3}}"      // should fail
  );

foreach ( $tests as $test )
{
  if ( preg_match( $pattern, $test, $matches ) )
  {
    echo $test, ': Matched!<pre>', print_r( $matches, 1 ), '
'; } еще { echo $ test, ': не соответствует = (
'; } }
...