Я хочу сопоставить строки, подобные приведенным ниже.
abc|q:1,f:2 cba|q:1,f:awd2,t:3awd,h:gr
Я использую php и preg_match
и preg_match_all
с этим выражением.
/^([az]+)\|([az]+:[a-z0-9]+,?)+$/iU
Это возвращает только первую часть перед трубой и одну a: 1. Что я делаю неправильно, почему он ведет себя таким образом и как я могу заставить его работать?
/^([az]+)\|((?:[az]+:[a-z0-9]+,?)+)$/iU
будет захватывать:
Жадная природа квантора «+» делает вашу группу захвата ([az] +: [a-z0-9] +,?) Захватывает только последний набор символов, соответствующих этому регулярному выражению.
/(?ms)^((?:[az]+)\|(?:[az]+:[a-z0-9]+,?)+)$/iU
захватит всю линию.
Обратите внимание на « ?:
», Чтобы избежать создания какой-либо группы захвата .
Я просто попробовал:
<?php $string = 'cba|q:1,f:awd2,t:3awd,h:gr'; $subpat = '[az]+:[a-z0-9]+'; $pat = "/^([az]+)\|($subpat(?:,$subpat)+)$/i"; preg_match( $pat, $string, $matches ); print_r( $matches ); ?>
который дает
Array ( [0] => cba|q:1,f:awd2,t:3awd,h:gr [1] => cba [2] => q:1,f:awd2,t:3awd,h:gr )
На этом этапе у вас есть часть перед вертикальной полосой в matches[1]
а остальные – в matches[2]
. Повторение $subpat
существует, чтобы гарантировать правильное разделение строк запятыми. После этого примените взрыв в matches[2]
.
$string = 'cba|q:1,f:awd2,t:3awd,h:gr'; $re = '~(?: ^(\w+)\| ) | (?: (\w+) : (\w+) (?:,|$) )~x'; preg_match_all($re, $string, $m, PREG_SET_ORDER); var_dump($m);
это будет соответствовать части перед трубой («ведущий») и всем парам ключ-значение одновременно. «lead» будет в $m[0][1]
а значения ключа будут в $m[1..x][2] and [3]
. Добавьте некоторую простую пост-обработку, чтобы преобразовать ее в полезную форму, например:
$lead = $m[0][1]; foreach(array_slice($m, 1) as $p) $data[$p[2]] = $p[3]; var_dump($lead, $data);