#php #regex
#php #регулярное выражение
Вопрос:
Вот пример строки:
$text = 'foo (20/50) bar () baz (11/30)';
Вывод, который мне нужен, это:
$items = array(
array(
"title" => "foo",
"number" => 20
),
array(
"title" => "bar",
"number" => 0
)
array(
"title" => "baz",
"number" => 11
)
);
Попытка
До сих пор я использовал
$matches_title = array();
$matches_number = array();
preg_match_all('!([^s] )!',$text,$matches_title);
preg_match_all('!(?<=()(d )(?=/)!',$text,$matches_number);
А затем перебор совпадений для получения значений. Очевидно, что это не работает, когда одна из круглых скобок пуста, поскольку оба массива будут иметь разную длину.
Как мне решить эту проблему?
Комментарии:
1. Вы можете предварительно обработать строку like
str_replace('()', '(0)', $text)
и запустить регулярное выражение для этой строки. Невозможно использовать «значение группы по умолчанию», регулярное выражение так не работает.
Ответ №1:
Вы можете использовать этот php-код:
$text = 'foo (20/50) bar () baz (11/30)';
preg_match_all('~([w-] )h*((d*)(?=[/)])~', $text, $m);
$items = array();
foreach($m[1] as $i => $v) {
$n = $m[2][$i];
$items[] = array( "title" => $v, "number" => (empty($n) ? 0: $n) );
}
print_r($items);
Вывод:
Array
(
[0] => Array
(
[title] => foo
[number] => 20
)
[1] => Array
(
[title] => bar
[number] => 0
)
[2] => Array
(
[title] => baz
[number] => 11
)
)
Комментарии:
1. Это также будет соответствовать
foo (30)
. Мы должны выяснить, возможно ли это и должно ли это быть включено в результат.2. @Barmar я не верю, что это возможно, но даже если бы это было так, это было бы приемлемо.
Ответ №2:
Другим вариантом может быть сопоставление формата вашей строки с использованием G
для утверждения позиции в конце предыдущего сопоставления и использования именованной группы захвата:
G(?<title>S )h ((?:(?<number>d )/d )?)(?:s|$)
Демонстрация регулярных выражений | Демонстрация PHP
Например:
$str = "foo (20/50) bar () baz (11/30)";
$pattern = '~G(?<title>S )h ((?:(?<number>d )/d )?)(?:s|$)~';
preg_match_all($pattern, $str, $matches, PREG_SET_ORDER, 0);
$matches = array_reduce($matches, function($carry, $item) {
$carry[] = [
"title" => $item["title"],
"number" => array_key_exists("number", $item) ? $item["number"] : 0
];
return $carry;
});
print_r($matches);
Результат:
Array
(
[0] => Array
(
[title] => foo
[number] => 20
)
[1] => Array
(
[title] => bar
[number] => 0
)
[2] => Array
(
[title] => baz
[number] => 11
)
)