【问题标题】:Filter array elements by searching for partial match in keys and values通过在键和值中搜索部分匹配来过滤数组元素
【发布时间】:2016-07-05 00:37:08
【问题描述】:

是否可以像在 MySQL 中一样在 PHP 数组中进行搜索。

例如:我有这个array

array(
  'mark@test.com'=> `Mark Mian`,
  'jhon@test.com'=> `John jack`,
  'logon@test.com'=> `Bob Logon`,
  'Stela@test.com'=> `Stela Josh`,
  'json@test.com'=> `Json Josh`
  'bobby@test.com'=> `Bob Mark`
)

我会做这种类型的搜索,

例如:如果我搜索 Mark 它应该返回这个

'mark@test.com' => `马克勉

如果我搜索 Bob 它应该返回我

'bobby@test.com'=> Bob Mark

'logon@test.com'=>Bob Logon,

如果我只搜索a,它应该返回那些包含a 的元素,例如:

'mark@test.com'=>Mark Mian,

'jhon@test.com'=>John jack,

'Stela@test.com'=>Stela Josh,

'bobby@test.com'=> Bob Mark

注意:搜索应按键或值

【问题讨论】:

  • 您可以为此使用 regexstr_pos。但是你尝试过什么吗?
  • 尝试使用preg_grep
  • @Qazi preg_grep 无法在数组键中搜索 - 如果需要,您应该在 array_keys($array) 上使用 preg_grep
  • @HankyPanky 你可以结合array_filterpreg_grep 来同时搜索两者;)
  • 如果问题是关于如何“模拟”WHERE col REGEXP 'PATTERN',我会发布基于preg_grep 的解决方案,但惠普的解决方案对于@987654343 来说已经足够了@ 不区分大小写的文字字符串搜索。

标签: php arrays regex search filtering


【解决方案1】:
$needle="bob";
$output=array();
foreach($array as $k=>$v)
{
   if(stristr($k,$needle) || stristr($v,$needle))
   $output[$k]=$v;
}
print_r($output);

Fiddle

也就是说,如果您想同时搜索键和值,如果您只想搜索值,请删除 keys 部分。

【讨论】:

  • 我最初会定义一个空的$output
  • @HankyPanky 我会调查一下,你对array_filter() 函数有什么建议,可以吗?
【解决方案2】:

这是一个preg_grep 解决方案,它应该更像 MySQL 中的WHERE REGEXP 'PATTERN'。我修改了Daniel Klein's preg_grep_keys function 以在数组键中搜索模式,并在其中添加了array_merge,它应该适用于具有非数字键的数组。如果键是数字,只需使用preg_grep solutionpreg_grep('~Mark~i', $arr); 查找所有具有markMark 等的数组元素)。

array_merge
将一个或多个数组的元素合并在一起,以便将一个数组的值附加到前一个数组的末尾。它返回结果数组。 如果输入数组具有相同的字符串键,则该键的后一个值将覆盖前一个。 但是,如果数组包含数字键,则后一个值不会覆盖原始值,但会被追加。

function preg_grep_keys_values($pattern, $input, $flags = 0) {
    return array_merge(
      array_intersect_key($input, array_flip(preg_grep($pattern, array_keys($input), $flags))),
      preg_grep($pattern, $input, $flags)
   );
}

$a = array(
  'mark@test.by.com'=> "Mark Mian lv",
  'jhon@test.lv.com'=> "John jack lv",
  'logon@test.en.com'=> "Bob Logon",
  'Stela@test.es.com'=> "Stela Josh",
  'json@test.es.com'=> "Json Josh",
  'bobby@test.lv.com'=> "Bob Mark"
);

$r = preg_grep_keys_values('~lv~i', $a);
print_r($r);

this IDEONE demo

上面的代码首先在键中搜索lv(不区分大小写),然后在值中,然后将结果合并到1个数组中。因此,结果是:

[jhon@test.lv.com] => John jack lv
[bobby@test.lv.com] => Bob Mark
[mark@test.by.com] => Mark Mian lv

【讨论】:

    【解决方案3】:

    一个简单的方法是使用array_filter

    如果你想要正则表达式,这会工作

    $regex = '~test~';
    $result = array_filter($data, function($item) use ($regex) {
        return preg_match($regex, $item);
    });
    

    或者只是一个简单的包含搜索

    $search = 'test';
    $result = array_filter($data, function($item) use ($search) {
        return stristr($value, $search);
    });
    

    如果您必须同时搜索 - 键和值,您可以将参数 ARRAY_FILTER_USE_BOTH 附加到 array_filter。

    $search = 'test';
    $result = array_filter($data, function($item, $key) use ($search) {
        return stristr($value, $search) || stristr($key, $search);
    }, ARRAY_FILTER_USE_BOTH);
    

    最后,您可以结合使用 array_filter 和 preg_grep 来同时搜索两者。

    $search = '~bob~i';
    $result = array_filter($data, function() use ($search) {
        return count(preg_grep($search, func_get_args()));
    }, ARRAY_FILTER_USE_BOTH);
    

    【讨论】:

    • 再抱歉。 '~bob~i'; 呢?:P。 +1 无论如何
    • @HankyPanky 我添加了一个同时搜索两者的 preg_grep 版本
    • 使用stristr 是个坏主意,因为1)您不需要提取子字符串,2)如果可以将needle参数评估为false,您将得到错误的结果,例如:if (stristr('abc0abc', '0')) echo 'toto';。您应该改用stripos,并通过严格的比较来测试它:return stripos(.....) !== false;
    【解决方案4】:

    您要过滤数组,请使用设计用于的array_filter

    如果只搜索文字字符串,则不需要使用正则表达式:

    $needle = 'bob';
    
    $result = array_filter($data, function ($k, $v) use ($needle) {
        return stripos($k, $needle) !== false || stripos($v, $needle) !== false;
    }, ARRAY_FILTER_USE_BOTH);
    

    如果您希望能够使用正则表达式进行过滤:

    $pattern = '~n.*e~i';
    
    $result = array_filter($data, function ($k, $v) use ($pattern) {
        return !empty(preg_grep($pattern, [$k, $v]));
    }, ARRAY_FILTER_USE_BOTH);
    

    【讨论】:

      【解决方案5】:
         $search = "Mark"
      
        $array = array(
        'mark@test.com'=> `Mark Mian`,
       'jhon@test.com'=> `John jack`,
       'logon@test.com'=> `Bob Logon`,
       'Stela@test.com'=> `Stela Josh`,
       'json@test.com'=> `Json Josh`
      'bobby@test.com'=> `Bob Mark`
       )
             foreach ($array as $key => $value) {
               if (stristr($value, $search) == '') {
              //not found
              }else{
            //found
             }
      

      这是搜索任何子字符串的最佳方法,不区分大小写且快速

      就像在mysql中一样

      例如:

      从 name = "%Mark%" 的表中选择 *

      【讨论】:

        【解决方案6】:

        从 PHP8 开始,str_contain() 成为首选的本地函数,可以在不减少语法的情况下进行不区分大小写的搜索。

        搜索小写的b 很好地展示了对键和值的不区分大小写的搜索。

        代码:(Demo)

        $array = [
            'mark@test.by.com'=> "Mark Mian lv",
            'jhon@test.lv.com'=> "John jack lv",
            'logon@test.en.com'=> "Bob Logon",
            'Stela@test.es.com'=> "Stela Josh",
            'json@test.es.com'=> "Json Josh",
            'bobby@test.lv.com'=> "Bob Mark"
        ];
        
        $needle = 'b';
        
        var_export(
            array_filter(
                $array,
                fn($v, $k) => str_contains($v, $needle) || str_contains($k, $needle),
                ARRAY_FILTER_USE_BOTH
            )
        );
        

        输出:

        array (
          'mark@test.by.com' => 'Mark Mian lv',
          'logon@test.en.com' => 'Bob Logon',
          'bobby@test.lv.com' => 'Bob Mark',
        )
        

        如果你想变得可爱并在array_filter() 中调用一个函数,那么你可以将$v$k 连接在一起,但是你会冒着匹配任意指定的分隔字符的风险。为了稳定性,每次迭代只需调用两次。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-10-19
          • 2010-12-31
          • 1970-01-01
          • 1970-01-01
          • 2014-09-01
          • 2018-12-25
          • 2016-02-28
          相关资源
          最近更新 更多