PHP的:数组键的情况下*不敏感*查找?


70
$myArray = array ('SOmeKeyNAme' => 7);  

我想$myArray['somekeyname']回来7
有没有一种方法,而无需操纵数组呢?

我不创建数组,因此无法控制其键


6
我认为如果不修改或复制数组就不可能做到这一点。您可以使用php函数array_change_key_case复制数组以更改键大小写。
ynh 2010年

这是最令人赞赏的答案,但它写在评论中……我问以上是否可能,答案是:否
shealtiel

一切皆有可能。PHP是开源的,因此只需更改一些内部组件并重新编译即可;)
dev-null-dweller 2010年

我不知道为您的实际任务匹配多个键的潜力。如果您知道所有键都是唯一的,例如在将它们全部转换为小写字母之后,那么您就不需要更新所有键,只需要迭代数组并对键执行不区分大小写的比较。重要的是,一旦找到匹配项,您应该立即使用breakreturn,这样就不会进行不必要的迭代。如果需要容纳匹配多个键的可能性,那么您将需要迭代所有AND强制将所有键降低或降低实际上会损坏您的数据。
mickmackusa

Answers:


89

选项1-更改创建数组的方式

如果没有线性搜索或更改原始数组,就无法执行此操作。最有效的方法是在插入AND和查找值时在键上使用strtolower

 $myArray[strtolower('SOmeKeyNAme')]=7;

 if (isset($myArray[strtolower('SomekeyName')]))
 {

 }

如果保留密钥的原始大小写对您很重要,则可以将其存储为该密钥的附加值,例如

$myArray[strtolower('SOmeKeyNAme')]=array('SOmeKeyNAme', 7);

选项2-创建辅助映射

当您更新问题以建议您无法做到这一点时,如何创建一个提供小写和区分大小写版本之间映射的数组呢?

$keys=array_keys($myArray);
$map=array();
foreach($keys as $key)
{
     $map[strtolower($key)]=$key;
}

现在,您可以使用此代码从小写字母中获取区分大小写的密钥

$test='somekeyname';
if (isset($map[$test]))
{
     $value=$myArray[$map[$test]];
}

这避免了使用小写键创建数组的完整副本的需求,这实际上是解决此问题的唯一方法。

选项3-创建阵列的副本

如果不需要对数组进行完整复制,则可以使用array_change_key_case创建具有小写字母键的副本。

$myCopy=array_change_key_case($myArray, CASE_LOWER);

4
我想知道是否存在直接的方法。我知道事实并非如此。您的答案是解决方法的一种可能
shealtiel 2010年

14
这里还有array_change_key_case可能会有所帮助。
xpy

@xpy:打算暗示同样的事情,也应该更有效。
Alix Axel 2013年

@xpy才是真正的答案!我使用oracle和mysql数据库,它们返回大写/小写键,因此“更改创建键的方式”是不可行的。此评论很好地解决了不兼容问题!
pid 2014年

虽然标头本身不是UTF-8,但我将使用$ map [mb_strtolower($ key)] = $ key; 利用PHP的多字节功能。
noderman 2014年

48

我知道这是一个比较老的问题,但是处理这个问题的最优雅的方法是使用:

array_change_key_case($myArray); //second parameter is CASE_LOWER by default

在您的示例中:

$myArray = array ('SOmeKeyNAme' => 7);
$myArray = array_change_key_case($myArray);

之后,$ myArray将包含所有小写键:

echo $myArray['somekeyname'] will contain 7

另外,您可以使用:

array_change_key_case($myArray, CASE_UPPER);

可在此处查看文档:http : //us3.php.net/manual/en/function.array-change-key-case.php


17

您可以使用ArrayAccessinterface创建一个使用数组语法的类。

$lower_array_object = new CaseInsensitiveArray;
$lower_array_object["thisISaKEY"] = "value";
print $lower_array_object["THISisAkey"]; //prints "value"

要么

$lower_array_object = new CaseInsensitiveArray(
    array( "SoMeThInG" => "anything", ... )
);
print $lower_array_object["something"]; //prints "anything"

class CaseInsensitiveArray implements ArrayAccess
{
    private $_container = array();

    public function __construct( Array $initial_array = array() ) {
        $this->_container = array_map( "strtolower", $initial_array );
    }

    public function offsetSet($offset, $value) {
        if( is_string( $offset ) ) $offset = strtolower($offset);
        if (is_null($offset)) {
            $this->container[] = $value;
        } else {
            $this->container[$offset] = $value;
        }
    }

    public function offsetExists($offset) {
        if( is_string( $offset ) ) $offset = strtolower($offset);
        return isset($this->_container[$offset]);
    }

    public function offsetUnset($offset) {
        if( is_string( $offset ) ) $offset = strtolower($offset);
        unset($this->container[$offset]);
    }

    public function offsetGet($offset) {
        if( is_string( $offset ) ) $offset = strtolower($offset);
        return isset($this->container[$offset])
            ? $this->container[$offset]
            : null;
    }
}

14

一种简单但可能昂贵的方法是制作一个副本,然后使用array_change_key_case($array_copy, CASE_LOWER),然后进行访问array_copy['somekeyname']


array_change_key_case不修改数组。它返回数组的副本。
马丁·普里克里

2

我将Paul Dixon的为键创建映射的思想与Kendall Hopkins的使用ArrayAccess的思想相结合接口保留访问PHP数组的熟悉方法结合。

结果是一个避免复制初始数组并允许透明的不区分大小写的访问,同时在内部保留键的大小写的类。限制:如果不区分大小写的相等键(例如“ Foo”和“ foo”)包含在初始数组中或被动态添加,则后面的条目将覆盖前面的条目(使这些键不可访问)。

诚然,在许多情况下,它的(imo)更加简单明了,只需按键即可将键小写$lowercasedKeys = array_change_key_case($array, CASE_LOWER);,如Mikpa所建议。

CaseInsensitiveKeysArray类

class CaseInsensitiveKeysArray implements ArrayAccess 
{
    private $container = array();
    private $keysMap   = array();

    public function __construct(Array $initial_array = array()) 
    {
        $this->container = $initial_array;

        $keys = array_keys($this->container);
        foreach ($keys as $key) 
        {
            $this->addMappedKey($key);
        }
    }

    public function offsetSet($offset, $value) 
    {
        if (is_null($offset)) 
        {
            $this->container[] = $value;
        }
        else 
        {
            $this->container[$offset] = $value;
            $this->addMappedKey($offset);
        }
    }

    public function offsetExists($offset) 
    {
        if (is_string($offset)) 
        {
            return isset($this->keysMap[strtolower($offset)]);
        }
        else 
        {
            return isset($this->container[$offset]);
        }
    }

    public function offsetUnset($offset) 
    {
        if ($this->offsetExists($offset)) 
        {
            unset($this->container[$this->getMappedKey($offset)]);
            if (is_string($offset)) 
            {
                unset($this->keysMap[strtolower($offset)]);
            }
        }
    }

    public function offsetGet($offset) 
    {
        return $this->offsetExists($offset) ? 
               $this->container[$this->getMappedKey($offset)] : 
               null;
    }

    public function getInternalArray() 
    {
        return $this->container;
    }

    private function addMappedKey($key) 
    {
        if (is_string($key)) 
        {
            $this->keysMap[strtolower($key)] = $key;
        }
    }

    private function getMappedKey($key) 
    {
        if (is_string($key)) 
        {
            return $this->keysMap[strtolower($key)];
        }
        else 
        {
            return $key;
        }
    }
}

2

从PHP网站

function array_ikey_exists($key, $haystack){
    return array_key_exists(strtolower($key), array_change_key_case($haystack));    
}

参考:http ://us1.php.net/manual/en/function.array-key-exists.php#108226


2

我还需要一种返回(第一个)不区分大小写的键匹配的方法。这是我想出的:

/**
 * Case-insensitive search for present array key
 * @param string $needle
 * @param array $haystack
 * @return string|bool The present key, or false
 */
function get_array_ikey($needle, $haystack) {
    foreach ($haystack as $key => $meh) {
        if (strtolower($needle) == strtolower($key)) {
            return (string) $key;
        }
    }
    return false;
}

因此,要回答原始问题:

$myArray = array('SOmeKeyNAme' => 7);
$test = 'somekeyname';
$key = get_array_ikey($test, $myArray);
if ($key !== false) {
    echo $myArray[$key];
}

1

将键分配给数组时,可以将其小写,而在查找值时,也可以将其小写。

无需修改数组,而是整个数据结构:

一个非常麻烦的方法涉及创建魔术的getter / setter方法,但这确实值得付出努力(请注意,其他方法也必须实现)?

<?php 

class CaseInsensitiveArray
{ 

  protected $m_values;

  public function __construct()
  {
    $this->m_values = array();
  } 

  public function __get($key)
  { 
    return array_key_exists($key, $this->m_values) ? $this->m_values[$key] : null;
  } 

  public function __set($key, $value)
  { 
    $this->m_attributes[$key] = $value;
  } 
} 

有很多方法可以做到这一点而又不会弄乱数据,但是他们真的值得为此烦恼吗?
icanhasserver

0

您可以手动遍历数组并搜索匹配项。

foreach( $myArray as $key => $value ) {
    if( strtolower( $key ) == 'somekeyname' ) {
        // match found, $value == $myArray[ 'SOmeKeyNAme' ]
    }
}

0

就我而言,我想要一种有效的解决方法,其中我的程序已经使用foreach循环从具有未知大小写的客户数据中创建了一个数组,并且希望保留客户的案例以供以后在程序中显示。

我的解决方案是创建一个单独的数组$ CaseMap,以将给定的小写字母映射到该数组中使用的大小写混合字母(此处省略了无关的代码):

$CaseMap=[];
foreach ($UserArray as $Key=>$Value)
    $CaseMap[strtolower($Key)]=$Key;

然后查找是这样的:

$Value=$UserArray[$CaseMap("key")];

而内存开销只是$ CaseMap数组,该数组大概将短键映射到短键。

我不确定在我尚未使用foreach的情况下,PHP是否具有更有效的方式来生成$ CaseMap。


0

我只是遇到了同样的问题,所以无法更改原始数组。我使用一些数组函数。

参量

$search = "AbCd";
$array = array("AbcD"=>"11","Bb"=>"22");

$lower_search = strtolower($search);
$array_of_keys = array_map("strtolower",array_keys($array));
$idx = array_search($lower_search,$array_of_keys);
if($idx !== FALSE)
    echo array_values($array)[$idx];

使其更短

if(($idx=array_search(strtolower($search),array_map("strtolower",array_keys($array))))!==FALSE)
    echo array_values($array)[$idx];

看来您没有阅读array_change_key_case()很多年前推荐的前两个答案。
mickmackusa

@mickmackusa你是对的。我试图使代码不复制值。但是我没有抓住,“ array_values”也可以复制。这没什么好了。
CN Lee

-1

我知道这很旧,但是万一其他人需要一种快速简便的方法来完成此操作,而无需实际更改原始数组:

function array_key_i($needle, $haystack){
  $key=array_search(strtolower($search), array_combine(array_keys($array),array_map('strtolower', array_keys($array))));
  return ($key!==false);
}

$array=array('TeSt1'=>'maybe');
$search='test1';

array_key_i($search, $array); // returns true
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.