如果关联键以特定子字符串开头,则保留数组中的元素

13
如果我有以下这样的数组:
array [
       y => 35
       x => 51
       z => 35
       c_3 => 4
       c_1 => 54
       c_6 => 53
       c_9 => 52
] 

我想获得数组:

array [c_3=>4, c_1=>54, c_6=>53, c_9=>52]

如何过滤掉没有以 c_ 开头的元素?


PHP8提供了更语义化/直观的本地函数来进行过滤,并避免了使用正则表达式的需要。在我的重复页面答案中展示:https://dev59.com/x2445IYBdhLWcg3wNXk_#65037675 - mickmackusa
7个回答

11

试试这个:

$filtred = array();

foreach($yourArray as $key => $value)
  if(preg_match('/c_\d/',$key))
    $filtred[] = $value;

print_r($filtred);

这个答案按键过滤并销毁结果数组中的键 - 可能不是期望的结果。 - mickmackusa

7

试一下这个

 //your array
    $arr1 = array (
           "y" => 35,
           "x" => 51,
           "z" => 35,
           "c_3" => 4,
           "c_1" => 54,
           "c_6" => 53,
           "c_9" => 52
    );
// Array with keys you want
    $arr2 =  array (
           "c_3" => '',
           "c_1" => '',
           "c_6" => '',
           "c_9" => ''
    );
//use array_intersect_key to find the common  ;)
    print_r(array_intersect_key($arr1,$arr2));

1
不错,我不知道这个命令。想了解更多关于 array_intersect_key 的信息的人可以访问:http://php.net/manual/en/function.array-intersect-key.php - Sven van Zoelen
1
这个未经解释的代码片段只有在所有所需的键都事先知道的情况下才能正常工作。 - mickmackusa

6

使用array_filter()检查此解决方案

 $arr = [
   'y' => 35,
   'x' => 51,
   'z' => 35,
   'c_3' => 4,
   'c_1' => 54,
   'c_6' => 53,
   'c_9' => 52,
 ];

 $filtered = array_filter($arr, function($v) use($arr){
   return preg_match('#c_\d#', array_search($v, $arr));
 });

下面的解决方案适用于PHP版本>=5.6.0
 $filtered = array_filter($arr, function($k){
   return preg_match('#c_\d#', $k);
 }, ARRAY_FILTER_USE_KEY);

这两种解决方案都有效,我已经检查过了。


preg_match('#c_\d#', array_search($v, $arr)) 是一个不好的想法。看看它失败了:演示。原因是因为 array_search() 返回第一个匹配值的键。这在任何脚本中都不应该被使用。 - mickmackusa

2

我尝试了上面的解决方案,但是在PHP 5.6中都没有起作用。

因此,我尝试并使用了不同的解决方案,这对我有用...

注:Original Answer翻译成"最初的回答"
$subArray = array();

foreach($arryDetails as $key => $value)
  if(preg_match('/^c_/',$key))
    $subArray[$key] = $value;

print_r($subArray);

"subArray"是一个误导性的变量数组。与其创建一个新的数组,不妨通过进行“unset()”调用来简单地改变原始数组。 - mickmackusa

2
你可以尝试使用array_filter()函数。
php文档页面上有一些有趣的例子。其中之一涵盖了过滤数组键的内容。

1
这个含糊的提示并没有解决这个问题。这个回答应该作为问题下方的评论更好。 - mickmackusa

0

array_slice()对于此任务没有任何好处。链接的页面也不相关--它演示了完整键过滤,而这个问题是根据部分键匹配进行过滤。 - mickmackusa

0

我之前也有类似的问题,并在这里寻找答案,但没有什么能满足我的期望。

我想要一个更可重用的解决方案,可以在所有项目中使用,所以最终我写了这个函数:

   /**
* Create a new a array containing only the key with a certain $pattern or $subString.
*
* Note: You cannot use both $subString and $pattern at once ($substring has precedence on $pattern).
*
* @param $errorMessage String to return the error message.
* @param $source Array in which we must extract data.
* @param $subString String/Int/Array substring (or array of substring) to seek in the key name.
* @param $pattern String regex for validating the key.
* @param $useValueAsKey Boolean if true it will use the value as the key in the new array (scalar values only).
*/
public static function extractSubArray(&$errorMessage, array &$source, $subString ="", $pattern = "", $useValueAsKey=false){
    
    $newArray = array();
    
    $errorMessage = "";
    
    $dbManager = GeneralDbManager::getInstance();
    
    if (empty($source)){
        
        $errorMessage = $dbManager->getErrorMessage("SOURCE_ARRAY_IS_EMPTY_ERR", "The array supplied is empty.");
    }
    elseif(empty($subString) and empty($pattern)){
        
        $errorMessage = $dbManager->getErrorMessage("NO_SUBSTR_OR_PATTERN_ERR", "There are no substring or pattern to match the keys in the array.");
    }
    elseif (!empty($subString) and !(is_string($subString) or is_numeric($subString) or is_array($subString))){
        
        $errorMessage = $dbManager->getErrorMessage("INVALID_MATCH_SUBSTRING_ERR", "The substring you supplied to match the keys is invalid.");
    }
    elseif(!empty($pattern) and !RegularExpression::testRegex($pattern)){
        
        $errorMessage = $dbManager->getErrorMessage("INVALID_MATCH_PATTERN_ERR", "The regular expression you supplied to match the keys is invalid.");
    }
    else{

        foreach ($source as $key => $value){
            
            if (self::isKeyMatchSubstring($key, $subString, $pattern)){
                
                if ($useValueAsKey and (is_string($value) or is_numeric($value))){
                    
                    $newArray[$value] = $value;     
                }
                else{
                    
                    $newArray[$key] = $value;
                }
            }       
        }
        
        if (empty($newArray)){
            
            $errorMessage = $dbManager->getErrorMessage("INVALID_MATCH_PATTERN_ERR", "We were not able to match any keys in the array with the substring or the regular expression.");
        }
    }
    
    unset($dbManager);
    
    return $newArray;
}

/**
* Validate that the $key contains the $substring (string or array) or match the $pattern.
*
* @param $key String to validate
* @param $subString String/Int/Array containing the subString to seek.
* @param $pattern String regex for validating the key.
*/
private static function isKeyMatchSubstring($key, $subString, $pattern){
    
    $matched = false;
    
    if (!empty($subString)){
        
        if (is_string($subString) or is_numeric($subString)){
            
            if(strpos(strtolower($key), strtolower($subString)) !== false){
                
                $matched = true;    
            }
        }
        else{ //array
            
            foreach($subString as $testString){
                
                $matched = self::isKeyMatchSubstring($key, $testString, "");
                    
                if ($matched){
                        
                    break;  
                }
            }
        }   
    }
    elseif(!empty($pattern)){
        
        $matched = preg_match($pattern, $key);
    }
    
    return $matched;
}

它使用一个名为testRegex()的函数,所以我想我也可以提供那段代码:

/**
* Make sure that a regular expression works in PHP.
*
* @param $regex String the regular expression to validate.
*
* @return Boolean
*/
public static function testRegex($regex){
    
    $isValid = false;
    
    if (!empty($regex) and is_string($regex)){
        
        if (@preg_match($regex, null) !== false){
            $isValid = true;
        }
    }
    
    return $isValid;
}

当然,没有单元测试的函数有多好呢?

    public function testExtractSubArray(){
    
    $errorMessage = "";
    
    $source = array();
    
    //no data
    $this->assertEmpty(Tool::extractSubArray($errorMessage, $source, "", "", false));
    
    $this->assertNotEmpty($errorMessage);
    
    //no substring or pattern
    $source = array(1 => 1);
    
    
    $this->assertEmpty(Tool::extractSubArray($errorMessage, $source, "", "", false));
    
    $this->assertNotEmpty($errorMessage);
    
    
    //invalid substring
    $dbmanager = GeneralDbManager::getInstance();
    
    $this->assertEmpty(Tool::extractSubArray($errorMessage, $source, $dbmanager, "", false));
    
    $this->assertNotEmpty($errorMessage);
    
    unset($dbmanager);
    
    
    //invalid pattern
    $this->assertEmpty(Tool::extractSubArray($errorMessage, $source, "", "[]123", false));
    
    $this->assertNotEmpty($errorMessage);
    
    
    //no match
    $this->assertEmpty(Tool::extractSubArray($errorMessage, $source, "pokemon", "", false));
    
    $this->assertNotEmpty($errorMessage);
    
    
    //valid substring
    $source = array("woot1" => "homer", "woot2" => "bart", "woot3" => "lisa", "doh1" => "marge", "doh2" => "simpson");
    
    $newArray = Tool::extractSubArray($errorMessage, $source, "WOOT", "", false);
    
    
    $this->assertNotEmpty($newArray);
    
    $this->assertEmpty($errorMessage);
    
    $this->assertContains("homer", $newArray);
    
    $this->assertContains("bart", $newArray);
    
    $this->assertContains("lisa", $newArray);
    
    $this->assertNotContains("marge", $newArray);
    
    $this->assertNotContains("simpson", $newArray);
    
    
    //use value as key
    $newArray = Tool::extractSubArray($errorMessage, $source, "WOOT", "", true);
    
    
    $this->assertTrue(array_key_exists("homer", $newArray));
    
    $this->assertTrue(array_key_exists("bart", $newArray));
    
    $this->assertTrue(array_key_exists("lisa", $newArray));
    
    
    //substring array
    $source = array("stan_march" => "normal", "kyle_brofloski" => "jew", "eric_cartman" => "asshole", "kenny_mccormick" => "dead", "butters_stotch" => "pushover");
    
    $newArray = Tool::extractSubArray($errorMessage, $source, array("stan", "kyle", "cartman"), "", false);
    
    
    $this->assertNotEmpty($newArray);
    
    $this->assertEmpty($errorMessage);
    
    $this->assertContains("normal", $newArray);
    
    $this->assertContains("jew", $newArray);
    
    $this->assertContains("asshole", $newArray);
    
    $this->assertNotContains("dead", $newArray);
    
    $this->assertNotContains("pushover", $newArray);
    
    
    //regex
    $source = array("jonathan@woot.ca" => 1, "jonathan" => 2, "12345" => 3, "more $$$" => 4, "$?%$?%$%?" => 5);
    
    $newArray = Tool::extractSubArray($errorMessage, $source, "", RegularExpression::ALPHA_NUMERIC, false);
    
    
    $this->assertNotEmpty($newArray);
    
    $this->assertEmpty($errorMessage);
    
    $this->assertNotContains(1, $newArray);
    
    $this->assertContains(2, $newArray);
    
    $this->assertContains(3, $newArray);
    
    $this->assertNotContains(4, $newArray);
    
    $this->assertNotContains(5, $newArray);
}

附加说明:此代码使用getErrorMessage()方法从数据库中获取错误消息的翻译。由于这些错误消息是为了调试目的而设计的,因此可以直接在代码中进行硬编码以提高性能(无需实例化类来获取错误消息并打开与数据库的连接)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接