подсчитать частоту данного слова в текстовом файле в Ruby

Я хочу иметь возможность подсчитывать количество вхождений заданного слова (например, ввода) в текстовом файле. У меня есть этот код, и он дает мне появление всех слов в файле:

word_count = {}
    my_word = id
    File.open("texte.txt", "r") do |f|
    f.each_line do |line|
    words = line.split(' ').each do |word|
      word_count[word] += 1 if word_count.has_key? my_word
      word_count[word] = 1 if not word_count.has_key? my_word
    end
  end
end

puts "\n"+ word_count.to_s

Спасибо


person Xibition    schedule 28.04.2017    source источник


Ответы (2)


Создайте тестовый файл

Давайте сначала создадим файл для работы.

text =<<-BITTER_END
It was the best of times, it was the worst of times, it was the age of wisdom,
it was the age of foolishness, it was the epoch of belief, it was the epoch of
incredulity, it was the season of Light, it was the season of Darkness, it was
the spring of hope, it was the winter of despair, we had everything before us,
we had nothing before us...
BITTER_END

FName = 'texte.txt'
File.write(FName, text)
  #=> 344

Укажите слово для подсчета

target = 'the'

Создайте регулярное выражение

r = /\b#{target}\b/i
  #=> /\bthe\b/i

Разрывы слов \b используются для того, чтобы, например, 'anthem' не считалось как 'the'.

Загружать небольшие файлы

Если, как здесь, файл не огромен, вы можете проглотить его:

File.read("texte.txt").scan(r).count
  #=> 10

Построчное чтение больших файлов

Если файл настолько велик, что мы хотели бы прочитать его построчно, сделайте следующее.

File.foreach(FName).reduce(0) { |cnt, line| cnt + line.scan(r).count }
  #=> 10

or

File.foreach(FName).sum { |line| line.scan(r).count }
  #=> 10

учитывая, что Enumerable#sum дебютировал в Руби v2.4.

См. IO::read и IO::foreach. (IO.methodx...обычно пишется как File.methodx.... Это разрешено, потому что File является подклассом IO, то есть File < IO #=> true.)

Используйте gsub, чтобы избежать создания временного массива

Первый метод (глотание файла) создает временный массив:

["the", "the", "the", "the", "the", "the", "the", "the", "the", "the"]

к которому применяется count (он же size). Один из способов избежать создания этого массива — использовать String#gsub вместо String#scan, как и первый, при использовании без блока возвращает перечислитель:

File.read("texte.txt").gsub(r).count
  #=> 10

Это также можно использовать для каждой строки файла.

Это нетрадиционное, но иногда полезное использование gsub.

person Cary Swoveland    schedule 28.04.2017
comment
Интересное использование gsub. Жаль, что text.count(r) не работает, было бы намного чище. - person Eric Duminil; 28.04.2017

Если вы хотите получить количество только определенного слова, нет необходимости использовать Hash, например:

word_count = 0
my_word = "input"

File.open("texte.txt", "r") do |f|
  f.each_line do |line|
    line.split(' ').each do |word|
      word_count += 1 if word == my_word
    end
  end
end

puts "\n" + word_count.to_s

word_count будет содержать общее количество вхождений my_word.


Если, с другой стороны, вы хотите подсчитать все слова, а затем просто вывести количество определенного слова, вы можете использовать Hash, но попробуйте что-то вроде этого:

word_count = Hash.new(0)
my_word = "input"

File.open("texte.txt", "r") do |f|
  f.each_line do |line|
    line.split(' ').each do |word|
      word_count[word] += 1
    end
  end
end

puts "\n" + word_count[my_word].to_s

word_count будет содержать все найденные слова с общим числом вхождений (слова являются ключами для Hash, а вхождения — их значениями); чтобы напечатать вхождения my_word, вам просто нужно получить значение хеша, используя my_word в качестве ключа.

person Gerry    schedule 28.04.2017
comment
Он продолжает давать мне 0 - person Xibition; 28.04.2017
comment
Или просто line.split(' ').count(my_word) - person Md. Farhan Memon; 28.04.2017