Группировка регулярных выражений со значением по умолчанию, если не найдено с помощью PHP

#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
        )

)