Нечувствительный к регистру массив # include? - PullRequest
46 голосов
/ 17 февраля 2012

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

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

Редактировать: Как насчет Array.include?.Все элементы массива являются строками.

Ответы [ 6 ]

56 голосов
/ 17 февраля 2012

Резюме

Если вы собираетесь проверять только одно слово в массиве или если содержимое вашего массива часто меняется, самый быстрый ответ - Аарон:

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

Если вы собираетесь тестировать много слов на статическом массиве, гораздо лучше использовать вариант ответа фарной: создайте копию массива, содержащую строчные версии ваших слов, и используйте 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' - это ответ Аррона, используя any? из моего комментария.
  • Тест 'downarray' - это ответ Фарной, воссоздавая новый массив в нижнем регистре для каждого из 1000 тестов.
  • Тест 'downonce' - это ответ Фарной, но он предварительно создает массив поиска только один раз.
  • Тест '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)

Если вы можете создать единственную копию массива в нижнем регистре один раз, чтобы выполнить множество поисков, ответ фарной будет лучшим (если вы должны использовать массив). Если вы можете создать 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, поскольку оно может выйти из цикла, как только найдет одно совпадение.

11 голосов
/ 17 февраля 2012

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

array.map(&:downcase).include?(string)

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

7 голосов
/ 17 февраля 2012

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

"abcdef".casecmp("abcde")     #=> 1
"aBcDeF".casecmp("abcdef")    #=> 0
"abcdef".casecmp("abcdefg")   #=> -1
"abcdef".casecmp("ABCDEF")    #=> 0
3 голосов
/ 02 января 2013

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

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

3 голосов
/ 17 февраля 2012
class String
    def caseinclude?(x)
        a.downcase.include?(x.downcase)
    end
end
0 голосов
/ 04 июля 2012

В моем случае, ваш пример не работает для меня. Я на самом деле хочу сделать это с любой «подстрокой».

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

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)}
=> []
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...