如何只返回带有preg_match或preg_match_all的命名组?

时间:2010-07-18 14:48:08

标签: php regex preg-match

示例:

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

在PHP的PDO对象中,有一个选项可以通过删除这些重复的编号值来过滤数据库中的结果:PDO::FETCH_ASSOC。但我还没有看到PHP中PCRE函数的类似修饰符。

9 个答案:

答案 0 :(得分:11)

preg_match没有任何标志或选项,它只返回命名匹配(尚未)。所以你想要的不是直接的。但是,您可以从匹配数组中删除所有带有非拟合键的项目,然后获得您想要的内容:

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

Demo

答案 1 :(得分:8)

  

如何仅使用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 over the elements and unset if array key 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;
}

它是一个名为dropNumericKeys()的简单PHP函数。它用于在使用命名组进行匹配的preg_match*()运行后对匹配数组进行后处理。函数接受$array。它迭代数组并删除/取消设置整数类型的所有键,保持字符串类型的键不变。最后,该函数返回数组&#34; now&#34;只有命名键。

注意:该函数用于PHP向下兼容性。它适用于所有版本。 array_filter解决方案依赖于常量ARRAY_FILTER_USE_KEY,它仅在PHP5.6 +上可用。见http://php.net/manual/de/array.constants.php#constant.array-filter-use-key

答案 2 :(得分:4)

我认为你不能让preg_*做到这一点,但你可以用一个简单的循环来做。但我不明白为什么这些元素会造成问题。

答案 3 :(得分:3)

还可以在返回之前取消设置所有数字索引:

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

答案 4 :(得分:1)

与上面发布的the answer类似,我使用此代码段来获取命名参数:

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

答案 5 :(得分:1)

我在你的帖子中读到这些可能是未来记忆的重载等... 在这种情况下,为什么不能用 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);

答案 6 :(得分:1)

您可以使用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'
    // ]   
});

答案 7 :(得分:0)

我使用了一些引入的代码,这是最终的代码适用于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);

如果您感兴趣它会从DJ文件无人机录制视频时生成的str文件中读取位置数据。

答案 8 :(得分:-1)

试试这个:

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