通过在键和值中搜索部分匹配来过滤数组元素

Posted

技术标签:

【中文标题】通过在键和值中搜索部分匹配来过滤数组元素【英文标题】: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 来说已经足够了@ 不区分大小写的文字字符串搜索。 【参考方案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 solution(preg_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 连接在一起,但是你会冒着匹配任意指定的分隔字符的风险。为了稳定性,每次迭代只需调用两次。

【讨论】:

以上是关于通过在键和值中搜索部分匹配来过滤数组元素的主要内容,如果未能解决你的问题,请参考以下文章

与参数匹配时返回对象的键和值[重复]

关联数组中的PHP三元语句来设置键和值?

php和laravel数组指定元素作为键和值

PHP获取数组最后一个元素的键和值

如何使用 django 在 developertools 中的 cookie 中添加键和值?

排序数组的键和值,键是Month