2010-02-09 3 views
1

У меня есть массив хэш, каждый хэш имеет два ключа: «от» и «до»Заменить слова из словаря

@dictionary = [{:to=>"lazy", :from=>"quick"}, {:to=>"flies", :from=>"jumps"}, {:from => "over the", :to => "under the"}] 

У меня есть несколько длинной строки

@text = "quick brown fox jumps over the lazy dog" 

Как я могу заменить все вхождения «от» предложений на «на» предложения словаря?

Вывод должен быть:

lazy brown fox flies under the lazy dog

Что является наиболее эффективным способом?

+1

Не имеет смысла хранить словарь как хэш? '@dictionary = {'lazy' => 'quick', 'flies' => 'jumps', 'над' => 'под'}' – kejadlen

ответ

3
@dictionary.each do |pair| 
    @text.gsub!(/#{pair[:from]}/, pair[:to]) 
end 

Или, если вы предпочитаете его на одной строке:

@dictionary.each { |pair| @text.gsub!(/#{pair[:from]}/, pair[:to]) } 

Это тот же самый код, используя только { } вместо do end для блока (который имеет тенденцию быть обычной рубиновой практикой).

+0

« все вхождения », поэтому вместо' sub' должно быть 'gsub'. – NVI

+0

Хорошая точка, спасибо NV. Обновлено сейчас. – mlambie

0
@dictionary.inject(@text) {|text, d| 
    text.gsub d[:from], d[:to] 
} 
+0

@dictionary = [{: to => "сумасшедший боб" : from => «lazy»}, {: to => «mad ben»,: from => «crazy bob»} «Быстрая коричневая лиса прыгает через сумасшедшую собаку» Как видите, тот же текст заменяется дважды, знает ли кто-нибудь одноразовое решение (не переопределяя предыдущие замены)? Хорошая работа @NV, спасибо – astropanic

+0

Какой результат вы ожидаете? «Быстрая коричневая лиса прыгает через сумасшедшую собаку» или нет? – NVI

+0

Я имею в виду в моем предыдущем комментарии, первая замена от ленивого к сумасшедшему бобу позже заменяется от сумасшедшего боба до безумного бен. Он не должен заменять существующие замены. – astropanic

0
@enhaced_dictionary = @dictionary.inject({}) {|res, e| res[e[:from]] = e[:to] } 
@compiled = @text.split(/\s/).map do |e| 
    @enhaced_dictionary[e] ? @enhaced_dictionary[e] : e 
end.join(' ') 
+0

'IndexError: строка не сопоставлена ​​ –

1

Если бы это были только слова без {"over the"=>"under the"}, тогда я думаю, что что-то вроде этого будет быстрее, чем сканирование строки снова и снова, как это делают большинство решений.

Сначала я преобразовать массив в чистом Hash

h=Hash.new 
@dictionary.each {|ft| h[ft[:from]]=ft[:to]} 
=> {"quick"=>"lazy", "over the"=>"under the", "jumps"=>"flies"} 

затем сканировать строку слово за словом

@text.split(/ /).each{|w| h[w] || w}.join(" ") 
=> "lazy brown fox flies over the lazy dog" 

Также не страдает от множественной проблемы замещения.

h["brown"]="quick" 
=> {"brown"=>"quick", "quick"=>"lazy", "over the"=>"under the", "jumps"=>"flies"} 
@text.split(/ /).each{|w| h[w] || w}.join(" ") 
=> "lazy quick fox flies over the lazy dog" 

Я сделал несколько тестов, и мне пришлось добавить много больше пара замены, чем я думал, прежде чем выше решения есть быстрее, чем gsub!.

require 'benchmark' 

@dictionary = [{:to=>"lazy", :from=>"quick"}, {:to=>"flies", :from=>"jumps"}, {:from => "over the", :to => "under the"}] 
@text = "quick brown fox jumps over the lazy dog" * 10000 
Benchmark.bm do |benchmark| 
    benchmark.report do 
    h=Hash.new 
    @dictionary.each {|ft| h[ft[:from]]=ft[:to]} 
    [email protected](/ /).each{|w| h[w] || w}.join(' ') 
    end 
    benchmark.report do 
    @dictionary.each { |pair| @text.gsub!(/#{pair[:from]}/, pair[:to]) } 
    end 

    @dictionary+=[{:to=>"black", :from=>"brown"}, {:to=>"ox", :from=>"fox"}, {:to=>"hazy", :from=>"lazy"}, {:to=>"frog", :from=>"dog"}] 
    @[email protected]*15 

    benchmark.report do 
    h=Hash.new 
    @dictionary.each {|ft| h[ft[:from]]=ft[:to]} 
    [email protected](/ /).each{|w| h[w] || w}.join(' ') 
    end 
    benchmark.report do 
    @dictionary.each { |pair| @text.gsub!(/#{pair[:from]}/, pair[:to]) } 
    end 
end 

Результаты:

 
     user  system  total  real 
    0.890000 0.060000 0.950000 ( 0.962106) 
    0.200000 0.020000 0.220000 ( 0.217235) 
    0.980000 0.060000 1.040000 ( 1.042783) 
    0.980000 0.030000 1.010000 ( 1.011380) 

gsub! раствор в 4,5 раза быстрее, только три пары замены. На 105 пар замена split решение, наконец, так же быстро, оно фактически только на 10% меньше, чем 105 пар замен, чем на три. gsub! получил пять раз медленнее.

+0

Я не думаю, что 'split' и' join' - хорошая идея. Что, если '@text =" ленивая быстрая лиса \ n летает над ленивой собакой "? – NVI

Смежные вопросы