Функция in_array без учета регистра в PHP

131

Возможно ли сравнение без учета регистра при использовании in_arrayфункции?

Итак, с таким исходным массивом:

$a= array(
 'one',
 'two',
 'three',
 'four'
);

Следующие запросы вернут истину:

in_array('one', $a);
in_array('two', $a);
in_array('ONE', $a);
in_array('fOUr', $a);

Какая функция или набор функций будут делать то же самое? Я не думаю, что in_arrayсама может это сделать.

leepowers
источник

Ответы:

101

вы можете использовать preg_grep():

$a= array(
 'one',
 'two',
 'three',
 'four'
);

print_r( preg_grep( "/ONe/i" , $a ) );
ghostdog74
источник
37
использование регулярных выражений не является хорошим решением, потому что это может быть медленным ... может быть, array_map быстрее
phil-opp
5
Для того, чтобы сделать его заменой для in_array, возвращая логическое значение, оно становится: count(preg_grep('/^'.preg_quote($needle).'/$',$a)>0). Значит, не так уж элегантно. (Обратите внимание, что символы ^ и $ необходимы, если не требуется частичное совпадение.) Однако, если вы действительно хотите, чтобы возвращались совпадающие записи, мне нравится это решение.
Даррен Кук,
2
Последний комментарий содержит синтаксическую ошибку: вместо / $ должно быть $ /.
Gogowitsch
1
@DarrenCook, насколько я знаю, приведение типа bool также будет работать (bool) preg_grep ('/ ^'. Preg_quote ($ Need). '$ /', $
A
8
Похоже, что более простой способ - просто преобразовать в нижний регистр.
Joshua Dance
229

Очевидно, что нужно просто преобразовать поисковый запрос в нижний регистр:

if (in_array(strtolower($word), $array)) { 
  ...

конечно, если в массиве есть прописные буквы, вам сначала нужно сделать это:

$search_array = array_map('strtolower', $array);

и ищите это. Нет смысла обрабатывать strtolowerвесь массив при каждом поиске.

Однако поиск по массивам является линейным. Если у вас большой массив или вы собираетесь делать это много, было бы лучше поместить условия поиска в ключ массива, так как это будет намного быстрее:

$search_array = array_combine(array_map('strtolower', $a), $a);

затем

if ($search_array[strtolower($word)]) { 
  ...

Единственная проблема здесь заключается в том, что ключи массива должны быть уникальными, поэтому при столкновении (например, «один» и «один») вы потеряете все, кроме одного.

Клетус
источник
23
Это должен быть принятый ответ. Добавление регулярных выражений иногда вызывает две проблемы.
Joshua Dance
1
Разве array_flip не был бы еще более быстрым решением вместо array_combine? $ search_array = array_flip (array_map ('strtolower', $ а));
jakub_jo 09
одна строка: in_array (strtolower ($ word), array_map ('strtolower', $ array))
Эндрю
1
@ Акира Ямамото - что с редактированием "исправить синтаксис" ? Нам не разрешено здесь исправлять код. Откатил.
Funk Forty
Или используйте array_change_key_case () secure.php.net/manual/en/function.array-change-key-case.php
boctulus
113
function in_arrayi($needle, $haystack) {
    return in_array(strtolower($needle), array_map('strtolower', $haystack));
}

Из документации

Тайлер Картер
источник
3
Вы должны блокировать код (или что-то еще), полученный откуда-то еще.
cletus
3
Просто быть чистым. Это не критика. Просто предложение (и только мое мнение, ничего официального). :) По крайней мере, если я скопирую фрагмент кода со страницы, я заблокирую его цитирование.
cletus
3
Кроме того, использование блока кода лучше описывает его, поскольку это «код». Блочное цитирование не позволяет правильно отформатировать его.
Тайлер Картер,
Я исправился, после того, как я использовал кнопку для добавления >в каждую строку, она работает. Я просто привык вручную ставить >в первую строку.
Тайлер Картер,
Я привык использовать для этого ctrl-Q. У этого есть одна проблема с блоками кода, потому что он по какой-то причине переносит строки. Не спрашивайте меня, почему. Но вы можете просто исправить это или вручную поставить точку >в начале каждой строки.
cletus
50
function in_arrayi($needle, $haystack) {
    return in_array(strtolower($needle), array_map('strtolower', $haystack));
}

Источник: страница руководства php.net in_array.

Gazler
источник
Если вы знаете, что находится в массиве, вы можете не указывать array_map; но это хороший пример.
Дон
2
Я действительно сделал. Потому что отображение массива при каждом вызове просто нелепо.
cletus
Кроме того, если предположить (как и Чача), это идет прямо из документации, лучше заблокировать его цитатой.
cletus
10

Скажем, вы хотите использовать in_array, вот как вы можете сделать поиск нечувствительным к регистру.

Без учета регистра in_array ():

foreach($searchKey as $key => $subkey) {

     if (in_array(strtolower($subkey), array_map("strtolower", $subarray)))
     {
        echo "found";
     }

}

Нормальный чувствительный к регистру:

foreach($searchKey as $key => $subkey) {

if (in_array("$subkey", $subarray))

     {
        echo "found";
     }

}
Майк Кью
источник
2

Вышесказанное верно, если мы предполагаем, что массивы могут содержать только строки, но массивы могут содержать и другие массивы. Также функция in_array () может принимать массив для $ Needle, поэтому strtolower ($ Need) не будет работать, если $ Needle является массивом, а array_map ('strtolower', $ haystack) не будет работать, если $ haystack содержит другие массивы, но это приведет к "предупреждению PHP: strtolower () ожидает, что параметр 1 будет строкой, заданным массивом".

Пример:

$needle = array('p', 'H');
$haystack = array(array('p', 'H'), 'U');

Поэтому я создал вспомогательный класс с соответствующими методами, чтобы делать проверки in_array () с учетом регистра и без учета регистра. Я также использую mb_strtolower () вместо strtolower (), поэтому можно использовать другие кодировки. Вот код:

class StringHelper {

public static function toLower($string, $encoding = 'UTF-8')
{
    return mb_strtolower($string, $encoding);
}

/**
 * Digs into all levels of an array and converts all string values to lowercase
 */
public static function arrayToLower($array)
{
    foreach ($array as &$value) {
        switch (true) {
            case is_string($value):
                $value = self::toLower($value);
                break;
            case is_array($value):
                $value = self::arrayToLower($value);
                break;
        }
    }
    return $array;
}

/**
 * Works like the built-in PHP in_array() function — Checks if a value exists in an array, but
 * gives the option to choose how the comparison is done - case-sensitive or case-insensitive
 */
public static function inArray($needle, $haystack, $case = 'case-sensitive', $strict = false)
{
    switch ($case) {
        default:
        case 'case-sensitive':
        case 'cs':
            return in_array($needle, $haystack, $strict);
            break;
        case 'case-insensitive':
        case 'ci':
            if (is_array($needle)) {
                return in_array(self::arrayToLower($needle), self::arrayToLower($haystack), $strict);
            } else {
                return in_array(self::toLower($needle), self::arrayToLower($haystack), $strict);
            }
            break;
    }
}
}
Alex
источник
1

Я написал простую функцию для проверки нечувствительного значения в массиве, код которого приведен ниже.

функция:

function in_array_insensitive($needle, $haystack) {
   $needle = strtolower($needle);
   foreach($haystack as $k => $v) {
      $haystack[$k] = strtolower($v);
   }
   return in_array($needle, $haystack);
}

как пользоваться:

$array = array('one', 'two', 'three', 'four');
var_dump(in_array_insensitive('fOUr', $array));
Джейк
источник
1
/**
 * in_array function variant that performs case-insensitive comparison when needle is a string.
 *
 * @param mixed $needle
 * @param array $haystack
 * @param bool $strict
 *
 * @return bool
 */
function in_arrayi($needle, array $haystack, bool $strict = false): bool
{

    if (is_string($needle)) {

        $needle = strtolower($needle);

        foreach ($haystack as $value) {

            if (is_string($value)) {
                if (strtolower($value) === $needle) {
                    return true;
                }
            }

        }

        return false;

    }

    return in_array($needle, $haystack, $strict);

}


/**
 * in_array function variant that performs case-insensitive comparison when needle is a string.
 * Multibyte version.
 *
 * @param mixed $needle
 * @param array $haystack
 * @param bool $strict
 * @param string|null $encoding
 *
 * @return bool
 */
function mb_in_arrayi($needle, array $haystack, bool $strict = false, ?string $encoding = null): bool
{

    if (null === $encoding) {
        $encoding = mb_internal_encoding();
    }

    if (is_string($needle)) {

        $needle = mb_strtolower($needle, $encoding);

        foreach ($haystack as $value) {

            if (is_string($value)) {
                if (mb_strtolower($value, $encoding) === $needle) {
                    return true;
                }
            }

        }

        return false;

    }

    return in_array($needle, $haystack, $strict);

}
Карлос Коэльо
источник
В заключение. Прошло 8 лет, прежде чем кто-то подошел и предоставил самую эффективную технику - раннююreturn . Когда нужно найти только одну иглу, бессмысленно продолжать итерацию после ее нахождения. Я бы исправил опечатку, ввел концепцию $ strict и сделал некоторые уточнения, возможно, что-то близкое к 3v4l.org/WCTi2 . Этот пост не идеален, но его суть в нужном месте.
mickmackusa
0
$a = [1 => 'funny', 3 => 'meshgaat', 15 => 'obi', 2 => 'OMER'];  

$b = 'omer';

function checkArr($x,$array)
{
    $arr = array_values($array);
    $arrlength = count($arr);
    $z = strtolower($x);

    for ($i = 0; $i < $arrlength; $i++) {
        if ($z == strtolower($arr[$i])) {
            echo "yes";
        }  
    } 
};

checkArr($b, $a);
омер
источник
1
Пожалуйста, опишите решение, которое вы предлагаете.
il_raffa
-2
  • in_array принимает следующие параметры: in_array (поиск, массив, тип)
  • если параметр поиска является строкой, а параметр типа установлен в значение ИСТИНА, поиск учитывает регистр.
  • поэтому для того, чтобы поиск игнорировал регистр, достаточно использовать его так:

$ a = array ('один', 'два', 'три', 'четыре');

$ b = in_array ('ОДИН', $ a, ложь);

user1077915
источник
6
Третий параметр определяет, проверяется ли тип переменной, а не случай . Когда trueбудут использоваться строгие сравнения типов, например '1' !== 1. Когда falseбудет использоваться жонглирование шрифтами, например '1' == 1. См. Документацию на php.net/in_array и php.net/manual/en/types.comparisons.php .
leepowers