Как считать абзацы в текстовом файле - PullRequest
0 голосов
/ 25 сентября 2018

Используя oliver.txt , напишите метод с именем count_paragraphs, который подсчитывает количество абзацев в тексте.

В oliver.txt разделитель абзацевсостоит из двух или более последовательных символов новой строки, например: \n\n, \n\n\n или даже \n\n\n\n.

Ваш метод должен возвращать либо число абзацев, либо ноль.

У меня есть этот код, но он не работает:

def count_paragraphs(some_file)
    file_content = open(some_file).read()
    count = 0
    file_content_split = file_content.split('')

    file_content_split.each_index do |index|
        count += 1 if file_content_split[index] == "\n" && file_content_split[index + 1] == "\n"                      
    end
    return count
end

# test code
p count_paragraphs("oliver.txt")

Ответы [ 3 ]

0 голосов
/ 25 сентября 2018

Для определения количества абзацев нет необходимости создавать массив и определять его размер.Вместо этого можно напрямую работать со строкой, создав счетчик и посчитав количество сгенерированных им элементов (после некоторой очистки содержимого файла).Это можно сделать с помощью нетрадиционной (но очень полезной) формы метода String # gsub .

Code

def count_paragraphs(fname)
  (File.read(fname).gsub(/ +$/,'') << "\n\n").gsub(/\S\n{2,}/).count
end

Примеры

Сначала создадим текстовый файл.

str =<<BITTER_END


Now is the time
for all good
Rubiest to take
a break.


Oh, happy
day.

One for all,
all for one.


Amen!
BITTER_END

  # "      \n\nNow is the time\nfor all good\nRubiest to take\na break.\n      \n     \nOh, happy\nday.\n\nOne for all,\nall for one.\n\n   \nAmen!\n"

Обратите внимание на встроенные пробелы.

FNAME = 'temp' 

File.write(FNAME, str)
  #=> 128

Теперь протестируйте метод с этим файлом.

count_paragraphs(FNAME)
  #=> 4

Еще один:

count_paragraphs('oliver.txt')
  #=> 61

Объяснение

первый шаг - работа с плохо сформированным текстом путем удаления пробелов непосредственно перед новыми строками:

File.read(fname).gsub(/ +$/,'')

  #=> "\n\nNow is the time\nfor all good\nRubiest to take\na break.\n\n\nOh, happy\nday.\n\nOne for all,\nall for one.\n\n\nAmen!\n"

Далее добавляются две строки, чтобы мы могли определитьвсе абзацы, включая последний, содержат непробельный символ, за которым следуют два или более символов новой строки. 1 .

Обратите внимание, что файлы, содержащие только пробелы и символы новой строки, содержат нулевые абзацы.

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

(File.read(fname) << "\n\n").gsub(/\S\n{2,}/).count

См. Перечислимый # count и IO # read .(Поскольку File.superclass #=> IO, read также является экземпляром метода класса File, и кажется, что он чаще вызывается в этом классе, чем в IO.)

Обратите внимание, что String#gsub безблок возвращает перечислитель (к которому применяется Enumerable#count),

В сторону: я считаю, что эта форма gsub была бы более широко использована, если бы она просто имела отдельное имя, такое как pattern_match.Называть его gsub кажется неправильным, поскольку оно не имеет ничего общего с «заменой», «глобальным» или иным образом.

1 Я пересмотрел свой первоначальный ответ, чтобы иметь дело с плохо сформированным текстом, ипри этом заимствовал идею @ Kimmo о требовании совпадений для включения непробельного символа.

0 голосов
/ 25 сентября 2018

Как насчет цикла, который запоминает предыдущий символ и состояние нахождения внутри или вне абзаца?

def count_paragraphs(some_file)
  paragraphs = 0
  in_paragraph = false
  previous_char = ""
  File.open(some_file).each_char do |char|
    if !in_paragraph && char != "\n"
      paragraphs += 1
      in_paragraph = true
    elsif in_paragraph && char == "\n" && previous_char == "\n"
      in_paragraph = false
    end
    previous_char = char
  end
  paragraphs
rescue
  nil
end

Это решение не создает никаких временных массивов полного содержимого, чтобы вы могли проанализироватьогромный файл без чтения в память.Также нет регулярных выражений.

rescue был добавлен из-за того, что «Ваша функция должна возвращать либо число абзацев, либо ноль», что не дает четкого определения того, когда должен быть возвращен ноль,В этом случае он будет возвращен в случае возникновения какого-либо исключения, например, если файл не найден или не может быть прочитан, что вызовет исключение, которое будет перехвачено rescue.

вами.не нужен явный return в Ruby.Возвращаемое значение последнего оператора будет использоваться как возвращаемое значение метода.

0 голосов
/ 25 сентября 2018

Гораздо проще либо посчитать его напрямую:

file_content.split(/\n\n+/).count

, либо сосчитать разделители и добавить один:

file_content.scan(/\n\n+/).count + 1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...