【问题标题】:How to return only named groups with preg_match or preg_match_all?如何仅返回带有 preg_match 或 preg_match_all 的命名组?
【发布时间】:2011-03-17 14:23:39
【问题描述】:

例子:

$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 函数的类似修饰符。

【问题讨论】:

  • 你可以使用T-RegxnamedGroups()方法。

标签: php regex preg-match


【解决方案1】:

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

目前 (PHP7) 不可能。 您将始终获得一个混合类型数组,其中包含数字键和命名键。

让我们引用 PHP 手册 (http://php.net/manual/en/regexp.reference.subpatterns.php):

这个子模式将在matches数组中被它的索引 正常的数字位置和名称。


为了解决这个问题,下面的代码 sn-ps 可能会有所帮助:

1.通过对数组键使用 is_string 检查来过滤数组(对于 PHP5.6+)

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

2。 foreach 遍历元素并取消设置 if 数组键 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。它迭代数组并删除/取消设置所有整数类型的键,保持字符串类型的键不变。最后,该函数返回带有“现在”唯一命名键的数组。

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

【讨论】:

  • 如果你有一个像#1这样简单的解决方案,为什么还要定义一个函数
  • 该函数用于PHP向下兼容。它适用于所有版本。 array_filter 解决方案依赖于常量ARRAY_FILTER_USE_KEY,该常量仅适用于 PHP5.6+。见php.net/manual/de/…
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

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

    【讨论】:

    • 在小型阵列中,这不会造成问题,但在具有大量模式的大型阵列中,可能存在内存需求高的问题。其次,这样看起来更干净,并且(使用这个不存在的修饰符)少了一行代码,因此出错的可能性更小。
    • 恰恰相反:因为这不能通过 PCRE 完成,所以您必须添加更多代码,这可能会出现更多问题。
    • 我的意思是数组中的附加元素。
    • 相反,如果我要求的这个修饰符存在,那么不需要额外的行,如果它是一个可以设置所有 pcre 函数首选项的全局修饰符会更好输出数组的设置模式我重复一遍:它是在 PDO 对象中完成的,它不能在 pcre 中完成?
    • 如您所说:PDO 基于对象,pcre 仍然是基于函数的。随着语言的发展,他们可能会在一段时间后对其进行更改。
    【解决方案4】:

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

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

    【讨论】:

      【解决方案5】:

      类似于上面 hakre 发布的the answer,我使用这个 sn-p 来获取命名参数:

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

      【讨论】:

        【解决方案6】:

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

        【讨论】:

          【解决方案7】:

          您可以使用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->get('date'); 
              // 2010-07-18
          
              $groups = $match->namedGroups(); 
              // [
              //   'date' => '2010-07-18'
              // ]   
          });
          

          【讨论】:

            【解决方案8】:

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

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

            【讨论】:

              【解决方案9】:

              试试这个:

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

              【讨论】:

              • 不,这是错误的,我的意思是一个修饰符来自动删除数字键,在 preg_match_all 可能产生的多分支数组上并不容易
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2015-12-24
              • 1970-01-01
              • 1970-01-01
              • 2011-08-28
              相关资源
              最近更新 更多