Подтвердить что ты не робот

Неверный регистр Массив # включает?

Я хочу знать, что лучший способ сделать методы String.include? игнорировать регистр. В настоящее время я делаю следующее. Какие-либо предложения? Спасибо!

a = "abcDE"
b = "CD"
result = a.downcase.include? b.downcase

Изменить: Как насчет Array.include?. Все элементы массива - это строки.

4b9b3361

Ответ 1

Резюме

Если вы собираетесь тестировать только одно слово против массива или если содержимое вашего массива изменяется часто, самым быстрым ответом является Aaron's:

array.any?{ |s| s.casecmp(mystr)==0 }

Если вы собираетесь тестировать много слов против статического массива, гораздо лучше использовать вариант ответа farnoy: создайте копию вашего массива со всеми строчными версиями ваших слов и используйте include?. (Предполагается, что вы можете освободить память для создания мутированной копии вашего массива.)

# Do this once, or each time the array changes
downcased = array.map(&:downcase)

# Test lowercase words against that array
downcased.include?( mystr.downcase )

Еще лучше, создайте Set из вашего массива.

# Do this once, or each time the array changes
downcased = Set.new array.map(&:downcase)

# Test lowercase words against that array
downcased.include?( mystr.downcase )

Мой первоначальный ответ ниже - очень плохой исполнитель и обычно не подходит.

Бенчмарки

Ниже приведены ориентиры для поиска 1000 слов со случайным корпусом в массиве чуть более 100 000 слов, где 500 слов будут найдены, а 500 не будут.

  • Текст 'regex' - это мой ответ здесь, используя any?.
  • Тест "casecmp" - это ответ Arron, используя any? из моего комментария.
  • Тест "downarray" - это ответ farnoy, воссоздающий новый уменьшенный массив для каждого из 1000 тестов.
  • Тест "downonce" - это ответ farnoy, но только предварительный создание массива поиска.
  • Тест 'set_once' создает Set из массива строк с нижним уровнем, один раз перед тестированием.
                user     system      total        real
regex      18.710000   0.020000  18.730000 ( 18.725266)
casecmp     5.160000   0.000000   5.160000 (  5.155496)
downarray  16.760000   0.030000  16.790000 ( 16.809063)
downonce    0.650000   0.000000   0.650000 (  0.643165)
set_once    0.040000   0.000000   0.040000 (  0.038955)

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

Если вам нравится, проверить код бенчмаркинга.


Оригинальный ответ

I (первоначально сказал, что я) лично создавал не зависящее от регистра регулярное выражение (для строкового литерала) и использовал бы это:

re = /\A#{Regexp.escape(str)}\z/i # Match exactly this string, no substrings
all = array.grep(re)              # Find all matching strings…
any = array.any?{ |s| s =~ re }   #  …or see if any matching string is present

Использование any? может быть немного быстрее, чем grep, поскольку он может выйти из цикла, как только он найдет одно совпадение.

Ответ 2

Для массива используйте:

array.collect {|el| el.downcase }.include? string

Регулярные выражения очень медленные и их следует избегать.

Ответ 3

Вы можете использовать casecmp для сравнения, игнорируя случай.

"abcdef".casecmp("abcde")     #=> 1
"aBcDeF".casecmp("abcdef")    #=> 0
"abcdef".casecmp("abcdefg")   #=> -1
"abcdef".casecmp("ABCDEF")    #=> 0

Ответ 4

class String
    def caseinclude?(x)
        a.downcase.include?(x.downcase)
    end
end

Ответ 5

my_array.map {|! С | c.downcase.strip}

где map! изменяет my_array, map вместо этого возвращает новый массив.

Ответ 6

В farnoy в моем случае ваш пример не работает для меня. Я действительно хочу сделать это с помощью "подстроки" любого.

Вот мой тестовый пример.

x = "<TD>", "<tr>", "<BODY>"
y = "td"
x.collect { |r| r.downcase }.include? y
=> false
x[0].include? y
=> false
x[0].downcase.include? y
=> true

Ваше дело работает с точным нечувствительным к регистру совпадением.

a = "TD", "tr", "BODY"
b = "td"
a.collect { |r| r.downcase }.include? b
=> true

Я все еще экспериментирую с другими предложениями здесь.

--- ИЗМЕНИТЬ ВСТАВИТЬ ПОСЛЕ ЗДЕСЬ ---

Я нашел ответ. Благодаря Дрю Олсен

var1 = "<TD>", "<tr>","<BODY>"
=> ["<TD>", "<tr>", "<BODY>"]
var2 = "td"
=> "td"
var1.find_all{|item| item.downcase.include?(var2)}
=> ["<TD>"]
var1[0] = "<html>"
=> "<html>"
var1.find_all{|item| item.downcase.include?(var2)}
=> []