Все решения имеют проблемы с ловлей плохих слов, если регистр не совпадает. Решение regex проще всего исправить, добавив флаг ignore-case:
badex = /\b(#{bad.split.join('|')})\b/i
Кроме того, использование "String".include?(" String ")
приведет к граничным проблемам с первым и последним словами в строке или строками, где целевые слова имеют знаки препинания или дефисы. Тестирование в таких ситуациях приведет к тому, что потребуется много другого кода. Поэтому я думаю, что решение регулярных выражений является лучшим. Это не самый быстрый, но он будет более гибким прямо из коробки, и, если другие алгоритмы будут настроены для обработки свертывания и составных слов, решение regex может вырваться вперед.
#!/usr/bin/ruby
require 'benchmark'
bad = 'foo bar baz comparison'
badex = /\b(#{bad.split.join('|')})\b/i
str = "What's the fasted way to check if any word from the bad string is within my comparison string, and what's the fastest way to remove said word if it's found?" * 10
n = 10_000
Benchmark.bm(20) do |x|
x.report('regex:') do
n.times { str.gsub(badex,'').gsub(' ',' ') }
end
x.report('regex with squeeze:') do
n.times{ str.gsub(badex,'').squeeze(' ') }
end
x.report('array subtraction') do
n.times { (str.split(' ') - bad.split(' ')).join(' ') }
end
end
Я сделал переменную str намного длиннее, чтобы подпрограммы работали немного сложнее.
user system total real
regex: 0.740000 0.010000 0.750000 ( 0.752846)
regex with squeeze: 0.570000 0.000000 0.570000 ( 0.581304)
array subtraction 1.430000 0.010000 1.440000 ( 1.449578)
Дох! Я слишком привык к тому, как другие языки справляются со своими тестами. Теперь у меня все работает и выглядит лучше!
Просто небольшой комментарий о том, что, по-видимому, пытается сделать ФП: удаление слов из черного списка легко обмануть, и боль, которую нужно поддерживать. L33t-sp34k упрощает просмотр слов. В зависимости от приложения, люди считают это игрой, чтобы найти способы отодвинуть оскорбительные слова за пределы фильтрации. Лучшее решение, которое я нашел, когда меня попросили поработать над этим, состояло в том, чтобы создать генератор, который бы создавал все варианты слова и помещал их в базу данных, где какой-то процесс мог проверить как можно скорее, а не в режиме реального времени. Проверка миллионов маленьких строк может занять некоторое время, если вы ищете длинный список оскорбительных слов; Я уверен, что мы могли бы придумать целый список вещей, которые кто-то посчитал бы оскорбительными, но это упражнение для другого дня.
Я не видел в Ruby ничего похожего на Perl Regexp :: Assemble , но это был хороший способ справиться с подобной проблемой. Вы можете передать массив слов, а также опции для свертывания и границ слов, и он будет выдавать шаблон регулярного выражения, который будет соответствовать всем словам, с их общностью, которая, как считается, приведет к наименьшему шаблону, который будет соответствовать всем словам в список. После этого возникает проблема с поиском того, какое слово в исходной строке соответствует совпадениям, найденным шаблоном, чтобы их можно было удалить. Различия в регистре слов и совпадениях в сложных словах делают эту замену более интересной.
И мы даже не будем вдаваться в слова, которые являются мягкими или оскорбительными в зависимости от контекста.
Я добавил немного более всеобъемлющий тест для теста вычитания массива, чтобы соответствовать тому, как он должен работать в реальном куске кода. В ответе указано предложение if
, теперь оно отражает его:
#!/usr/bin/env ruby
require 'benchmark'
bad = 'foo bar baz comparison'
badex = /\b(#{bad.split.join('|')})\b/i
str = "What's the fasted way to check if any word from the bad string is within my comparison string, and what's the fastest way to remove said word if it's found?" * 10
str_split = str.split
bad_split = bad.split
n = 10_000
Benchmark.bm(20) do |x|
x.report('regex') do
n.times { str.gsub(badex,'').gsub(' ',' ') }
end
x.report('regex with squeeze') do
n.times{ str.gsub(badex,'').squeeze(' ') }
end
x.report('bad.any?') do
n.times {
if (bad_split.any? { |bw| str.include?(bw) })
(str_split - bad_split).join(' ')
end
}
end
x.report('array subtraction') do
n.times { (str_split - bad_split).join(' ') }
end
end
с двумя тестовыми прогонами:
ruby test.rb
user system total real
regex 1.000000 0.010000 1.010000 ( 1.001093)
regex with squeeze 0.870000 0.000000 0.870000 ( 0.873224)
bad.any? 1.760000 0.000000 1.760000 ( 1.762195)
array subtraction 1.350000 0.000000 1.350000 ( 1.346043)
ruby test.rb
user system total real
regex 1.000000 0.010000 1.010000 ( 1.004365)
regex with squeeze 0.870000 0.000000 0.870000 ( 0.868525)
bad.any? 1.770000 0.000000 1.770000 ( 1.775567)
array subtraction 1.360000 0.000000 1.360000 ( 1.359100)