Получите больше обратных ссылок из регулярного выражения, чем скобки

Ок, это действительно сложно объяснить на английском, поэтому я просто приведу пример.

Я буду иметь строки в следующем формате:

key-value;key1-value;key2-... 

и мне нужно извлечь данные как массив

 array('key'=>'value','key1'=>'value1', ... ) 

Я планировал использовать regexp для достижения (большей части) этой функциональности и написал это регулярное выражение:

 /^(\w+)-([^-;]+)(?:;(\w+)-([^-;]+))*;?$/ 

для работы с preg_match и этим кодом:

 for ($l = count($matches),$i = 1;$i<$l;$i+=2) { $parameters[$matches[$i]] = $matches[$i+1]; } 

Однако regexp явно возвращает только 4 обратных ссылок – первую и последнюю пары ключ-значение входной строки. Есть ли способ обойти это? Я знаю, что я могу использовать регулярное выражение только для проверки правильности строки и использования PHP- explode в циклах с отличными результатами, но мне действительно интересно, возможно ли это с помощью регулярных выражений.

Короче говоря, мне нужно зафиксировать произвольное количество этих key-value; пары в строке с помощью регулярных выражений.

Related of "Получите больше обратных ссылок из регулярного выражения, чем скобки"

Вы можете использовать lookahead для проверки ввода при извлечении совпадений:

 /\G(?=(?:\w++-[^;-]++;?)++$)(\w++)-([^;-]++);?/ 

(?=(?:\w++-[^;-]++;?)++$) является частью проверки. Если вход недействителен, совпадение будет сбой немедленно, но просмотр всегда будет оцениваться каждый раз, когда применяется регулярное выражение. Чтобы сохранить его (вместе с остальным регулярным выражением) в синхронизации с парами ключ-значение, я использовал \G чтобы привязать каждое соответствие к тому месту, где закончился предыдущий матч.

Таким образом, если просмотр впервые в первый раз, он будет гарантированно преуспеть в последующее время. Очевидно, что это не так эффективно, как могло бы быть, но это, вероятно, не будет проблемой – только ваше тестирование может точно сказать.

Если lookahead не работает, preg_match_all() вернет ноль (false). Если это удастся, совпадения будут возвращены в массиве массивов: один для полных пар ключ-значение, один для ключей, один для значений.

regex – мощный инструмент, но иногда это не лучший подход.

 $string = "key-value;key1-value"; $s = explode(";",$string); foreach($s as $k){ $e = explode("-",$k); $array[$e[0]]=$e[1]; } print_r($array); 

preg_match_all() этого используйте preg_match_all() . Может быть, что-то вроде:

 $matches = $parameters = array(); $input = 'key-value;key1-value1;key2-value2;key123-value123;'; preg_match_all("/(\w+)-([^-;]+)/", $input, $matches, PREG_SET_ORDER); foreach ($matches as $match) { $parameters[$match[1]] = $match[2]; } print_r($parameters); 

РЕДАКТИРОВАТЬ:

чтобы сначала проверить, соответствует ли входная строка шаблону, а затем просто используйте:

 if (preg_match("/^((\w+)-([^-;]+);)+$/", $input) > 0) { /* do the preg_match_all stuff */ } 

EDIT2: конечная точка с запятой является необязательной

 if (preg_match("/^(\w+-[^-;]+;)*\w+-[^-;]+$/", $input) > 0) { /* do the preg_match_all stuff */ } 

Нет. Новые совпадения перезаписывают старые совпадения. Возможно, limit аргумент explode() был бы полезен при взрыве.

как насчет этого решения:

 $samples = array( "good" => "key-value;key1-value;key2-value;key5-value;key-value;", "bad1" => "key-value-value;key1-value;key2-value;key5-value;key-value;", "bad2" => "key;key1-value;key2-value;key5-value;key-value;", "bad3" => "k%ey;key1-value;key2-value;key5-value;key-value;" ); foreach($samples as $name => $value) { if (preg_match("/^(\w+-\w+;)+$/", $value)) { printf("'%s' matches\n", $name); } else { printf("'%s' not matches\n", $name); } } 

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