Получите больше обратных ссылок из регулярных выражений, чем в скобках - PullRequest
1 голос
/ 11 февраля 2010

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

У меня будут строки в следующем формате:

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

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

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

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

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

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

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

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

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

Ответы [ 6 ]

2 голосов
/ 12 февраля 2010

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

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

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

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

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

2 голосов
/ 11 февраля 2010

Используйте взамен 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 */
}       
2 голосов
/ 11 февраля 2010

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

$string = "key-value;key1-value";
$s = explode(";",$string);
foreach($s as $k){
    $e = explode("-",$k);
    $array[$e[0]]=$e[1];
}
print_r($array);
0 голосов
/ 11 февраля 2010

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

0 голосов
/ 11 февраля 2010

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

$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);
    }
}
0 голосов
/ 11 февраля 2010

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

...