Хорошо, это действительно сложно объяснить на английском, поэтому я просто приведу пример.
Я буду иметь строки в следующем формате:
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;
в строке с помощью регулярных выражений.
Вы можете использовать lookahead для проверки ввода при извлечении совпадений:
/\G(?=(?:\w++-[^;-]++;?)++$)(\w++)-([^;-]++);?/
(?=(?:\w++-[^;-]++;?)++$)
является частью проверки. Если вход недействителен, совпадение будет сбой немедленно, но просмотр всегда будет оцениваться каждый раз, когда применяется регулярное выражение. Чтобы сохранить его (вместе с остальным регулярным выражением) в синхронизации с парами ключ-значение, я использовал \G
для привязки каждого соответствия к тому месту, где закончилось предыдущее совпадение.
Таким образом, если lookahead будет успешным в первый раз, он гарантирует успешное выполнение каждого последующего времени. Очевидно, что это не так эффективно, как могло бы быть, но это, вероятно, не будет проблемой - только ваше тестирование может точно сказать.
Если сбой просмотра невозможен, preg_match_all()
будет возвращать ноль (false). Если это удастся, совпадения будут возвращены в массиве массивов: один для полных пар ключ-значение, один для ключей, один для значений.
Используйте 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);
EDIT:
чтобы сначала проверить, соответствует ли входная строка шаблону, а просто используйте:
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 */
}
regex - мощный инструмент, но иногда его не лучший подход.
$string = "key-value;key1-value";
$s = explode(";",$string);
foreach($s as $k){
$e = explode("-",$k);
$array[$e[0]]=$e[1];
}
print_r($array);
I know I can use regex just to test the correctness of the string and use PHP's explode in loops with perfect results
Я не думаю, что вы можете выполнять проверку и извлечение данных с помощью одного единственного регулярного выражения, поскольку для проверки необходимы привязки (^
и $
) и preg_match_all()
для данных, но если вы используете привязки с помощью preg_match_all()
он вернет только последний сопоставленный набор.
как насчет этого решения:
$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);
}
}
;
не требуется. Также это только проверяет ввод, я хотел бы, чтобы регулярное выражение проверяло И создавало массив.
Нет. Новые совпадения перезаписывают старые совпадения. Возможно, аргумент limit
explode()
был бы полезен при взрыве.
+
и приму его, если никто не предложит лучшего решения, но регулярное выражение не проверяет данную строку ('foo-bar-baz'
будет считаться действительным ценности)'foo-bar-baz'
вы хотите'foo' => 'bar-baz'
или'foo-bar' => 'baz'
? я могу легко дать вам альтернативное регулярное выражение;)