Как вернуть только именованные группы с preg_match или preg_match_all? - PullRequest
14 голосов
/ 18 июля 2010

Пример:

$string = "This is some text written on 2010-07-18.";
preg_match('|(?<date>\d\d\d\d-\d\d-\d\d)|i', $string, $arr_result);
print_r($arr_result);

Возвращает:

Array
(
    [0] => 2010-07-18
    [date] => 2010-07-18
    [1] => 2010-07-18
)

Но я хочу, чтобы это было:

Array
(
    [date] => 2010-07-18
)

В объекте PDO PHP есть опция, которая фильтрует результаты из базы данных, удаляя эти дублирующиеся пронумерованные значения: PDO::FETCH_ASSOC. Но я еще не видел подобного модификатора для функций PCRE в PHP.

Ответы [ 9 ]

11 голосов
/ 18 ноября 2011

preg_match не имеет флага или параметра, который возвращает только именованные совпадения (пока). Так что то, что вы хотите, напрямую невозможно. Однако вы можете удалить все элементы с неподходящими ключами из массива совпадений, и тогда вы получите то, что ищете:

$matches = array_intersect_key($matches, array_flip(array('name', 'likes')));

Демо

9 голосов
/ 11 января 2016

Как вернуть только именованные группы с preg_match или preg_match_all?

В настоящее время (PHP7) это невозможно.Вы всегда получите массив смешанного типа, содержащий числовые и именованные ключи.

Давайте процитируем руководство по PHP (http://php.net/manual/en/regexp.reference.subpatterns.php):

Этот подшаблон будет затем проиндексирован в массиве совпадений по его обычной числовой позиции, а также по имени.


Для решения этой проблемы могут помочь следующие фрагменты кода:

1. отфильтровать массив с помощью проверки is_string для ключа массива (для PHP5.6 +)

$array_filtered = array_filter($array, "is_string", ARRAY_FILTER_USE_KEY);

2. Foreach для элементов и сбрасывать, если ключ массива is_int () (все версии PHP)

/**
 * @param array $array
 * @return array
 */
function dropNumericKeys(array $array)
{
    foreach ($array as $key => $value) {
        if (is_int($key)) {
            unset($array[$key]);
        }
    }
    return $array;
}

Это простая функция PHP с именем dropNumericKeys(). Используется для последующей обработки массива совпадений после выполнения preg_match*() с использованием именованных групп для сопоставления. Функции принимают $array. Он выполняет итерацию массива и удаляет / отменяет сброс всех ключей с целочисленным типом, оставляя ключи стип строки без изменений. Наконец, функция возвращает массив только с именованными ключами "now".

Примечание: функция предназначена для совместимости с PHP в обратном направлении. Она работает во всех версиях. Решение array_filter основано на константеARRAY_FILTER_USE_KEY, что толькодоступно на PHP5.6 +.См http://php.net/manual/de/array.constants.php#constant.array-filter-use-key

4 голосов
/ 18 июля 2010

Я не думаю, что вы можете заставить preg_* сделать это, но вы можете сделать это с помощью простого цикла. Но я не понимаю, почему эти элементы создают проблему.

3 голосов
/ 29 августа 2013

Также возможно сбросить все числовые индексы перед возвратом:

foreach (range(0, floor(count($arr_result) / 2)) as $index) {
    unset($arr_result[$index]);
}
1 голос
/ 12 ноября 2018

Вы можете использовать T-Regx и использовать group() или namedGroups(), который возвращает только именованные группы захвата.

<?php
$subject = "This is some text written on 2010-07-18.";

pattern('(?<date>\d\d\d\d-\d\d-\d\d)', 'i')->match($subject )->first(function ($match) {

    $date = $match->group('date'); 
    // 2010-07-18

    $groups = $match->namedGroups(); 
    // [
    //   'date' => '2010-07-18'
    // ]   
});
1 голос
/ 28 июля 2017

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

$string = "This is some text written on 2010-07-18.";
preg_match('|(?<date>\d{4}-\d{2}-\d{2})|i', $string, $arr_result);
$date = array("date" => $arr_result['date']);
unset($arr_result, $string);//delete array and string preg_match origen

print_r($date);
//or create a new:
//  $arr_result = $date;
//print_r($arr_result);
1 голос
/ 30 июля 2014

Аналогично ответу , который выложил выше, я использую этот фрагмент, чтобы получить только названные параметры:

<code>$subject = "This is some text written on 2010-07-18.";
$pattern = '|(?<date>\d\d\d\d-\d\d-\d\d)|i';
preg_match_all($pattern, $subject, $matches, PREG_SET_ORDER);
echo '<pre>Before Diff: ', print_r($matches, 1), '
'; $ match = array_diff_key ($ совпадений [0], диапазон (0, количество ($ совпадений [0]))); echo '
After Diff: ', print_r($matches, 1), '
';

... который производит это:

Before Array
(
    [0] => Array
        (
            [0] => 2010-07-18
            [date] => 2010-07-18
            [1] => 2010-07-18
        )

)
After Array
(
    [date] => 2010-07-18
)
0 голосов
/ 11 января 2018

Я использую некоторые из введенных кодов, и это последний код, работающий на php 5.6 +:

$re = '/\d+\r\n(?<start>[\d\0:]+),\d+\s--\>\s(?<end>[\d\0:]+),.*\r\nHOME.*\r\nGPS\((?<x>[\d\.]+),(?<y>[\d\.]+),(?<d>[\d\.]+)\)\sBAROMETER\:(?<h>[\d\.]+)/';

$str= file_get_contents($srtFile);
preg_match_all($re, $str, $matches, PREG_SET_ORDER, 0);
echo '<pre>';
$filtered=array_map(function ($d){
     return $array_filtered = array_filter($d, "is_string", ARRAY_FILTER_USE_KEY);
    },$matches);
var_dump($filtered);

, если вам интересно, что он делает, это считывает данные о положении из файла str, который дроны DJI генерируют во времязапись видео.

0 голосов
/ 18 июля 2010

Попробуйте это:

$string = "This is some text written on 2010-07-18."; 
preg_match('|(?<date>\d\d\d\d-\d\d-\d\d)|i',$string,$arr_result);
echo $arr_result['date'];
...