Как вернуть только именованные группы с preg match или preg match all?

пример:

$string = "This is some text written on 2010-07-18.";
preg_match('|(?<date>dddd-dd-dd)|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.

8 ответов


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


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

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

демо


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

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

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

этот подшаблон затем будет индексироваться в массиве matches его нормальное численное положение и также мимо имя.


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

1. отфильтруйте массив с помощью проверки is_string на ключе массива (для РНР5.6+)

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

2. foreach над элементами и unset, если ключ массива 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 нисходящей совместимости. Он работает на всех версиях. The array_filter решение зависит от константы ARRAY_FILTER_USE_KEY, который доступен только на PHP5.6+. Видеть http://php.net/manual/de/array.constants.php#constant.array-filter-use-key


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

foreach (range(0, floor(count($arr_result) / 2)) as $index) {
    unset($arr_result[$index]);
}

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

$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), '</pre>';
$matches = array_diff_key($matches[0], range(0, count($matches[0])));
echo '<pre>After Diff: ', print_r($matches, 1), '</pre>';

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

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

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

Я прочитал в вашем посте, что это возможные перегрузки будущей памяти и т. д... В этом случае, почему нет не может быть решена с помощью 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);

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

$re = '/\d+\r\n(?<start>[\d:]+),\d+\s--\>\s(?<end>[\d:]+),.*\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 дроны генерируют во время записи видео.


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

$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'];