частный метод `puts’ вызывается для «string»: String (nometoderror)

#ruby

#ruby

Вопрос:

Я использую ruby: 1.9.3

Файл с именем restaurant.txt который имеет такие данные, как этот:

 |"Aloo Fry"| "Carbohydrates bahut hai" | "Nahi Khana"
|"Moong"| "protein bahut hai" | "Khana Hai"
|"Egg"|"Protein hai but non veg"| "Nahi khana hai"
  

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

 Nahi Khana 
Khana Hai 
Nahi Khana hai
  
 if ARGV.length != 1
  puts "Input only the one file at a time"
  exit
end
foodie = ARGV[0]
puts "you have entered file: #{foodie}"
puts "Hold your horses... we are processing"
File.open(foodie, "r ").each do |line|
  new_line = line.split("|")[-1]
  puts new_line
  line.puts new_line
end
  

Я получаю сообщение об ошибке:

 private method `puts' called for "Nahi Khana":String (NoMethodError)
  

Комментарии:

1. Я полагаю, вы знаете, что поддержка Ruby версии v1.9.3 закончилась более четырех лет назад (23 февраля 2015 года).

2. да, не могу заставить промышленность изменить версию 🙂

Ответ №1:

@Whooper определил проблему с вашим кодом. Поэтому я решил предложить другой подход к созданию нужного файла.

Давайте сначала создадим файл, содержащий строку, указанную в вашем примере.

 FName = 'temp'
str =<<END
|"Aloo Fry"| "Carbohydrates bahut hai" | "Nahi Khana"
|"Moong"| "protein bahut hai" | "Khana Hai"
|"Egg"|"Protein hai but non veg"| "Nahi khana hai"
END

File.write(FName, str)
  #=> 149 (characters)
  

Подтвердите его содержимое:

 puts File.read(FName)
|"Aloo Fry"| "Carbohydrates bahut hai" | "Nahi Khana"
|"Moong"| "protein bahut hai" | "Khana Hai"
|"Egg"|"Protein hai but non veg"| "Nahi khana hai"
  

Вы можете прочитать файл и использовать String#scan с простым регулярным выражением и Array#join для построения строки, которую вы хотите сохранить.

 s = File.read(FName).scan(/"[^|] $/).join("n")
  #=> ""Nahi Khana"n"Khana Hai"n"Nahi khana hai"n" 
puts s
"Nahi Khana"
"Khana Hai"
"Nahi khana hai"
  

Регулярное выражение гласит: «сопоставьте двойную кавычку, за которой следуют все символы, кроме pipe ( "|" ), с концом строки». Каждое совпадение будет начинаться с первой двойной кавычки, следующей за последней строкой в строке.

Наконец, s выполните обратную запись в тот же файл, перезаписав его содержимое.

 File.write(FName, s)
  #=> 42
  

Посмотрите.

 puts File.read(FName)
"Nahi Khana"
"Khana Hai"
"Nahi khana hai"
  

Использование IO::read иногда называют глотанием файла (в виде строки).1 Это нормально, если файл не слишком большой. Если это очень большой файл, может потребоваться прочитать файл построчно, изменить строку, а затем записать это во временный файл. Когда временный файл завершен, исходный файл может быть удален и, при желании, временный файл может быть переименован в имя исходного файла. Вы могли бы сделать это следующим образом.

 TMP_FName = 'tmp'

f = File.open(TMP_FName, 'w')
File.foreach(FName) do |line|
  f.puts line.scan(/"[^|] $/).join("n")
end
f.close
File.delete(FName)
File.rename(TMP_FName, FName)
  

Подтвердите:

 puts File.read(FName)
"Nahi Khana"
"Khana Hai"
"Nahi khana hai"
  

1 Я не знаю, существует ли сопоставимый термин для использования ввода-вывода #write; возможно, выгрузка строки в файл. Хотя read и write являются IO методами (класса), они обычно задействованы в классе File . Это нормально, потому File.superclass #=> IO что , so File наследует эти методы от IO .

Комментарии:

1. Да, мой файл очень большой, иногда он составляет от 500 МБ до 1 ГБ. Я пробую ваше решение, получаю некоторую ошибку кодирования, которую я исправлю.

Ответ №2:

Это утверждение line.puts new_line вызывает ошибку.

Я предполагаю, что то, чего вы хотите достичь здесь, это записать new_line в ваш выходной файл, и, возможно, вы подумали, что line это файловый объект, которого нет, потому line что это a string , который содержит каждую строку, прочитанную из вашего входного файла. Кроме того, ваш метод File.open предназначен только read-only state для того, чтобы вы не могли записывать в этот файл.

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

 if ARGV.length != 1
  puts "Input only the one file at a time"
  exit
end
foodie = ARGV[0]
puts "you have entered file: #{foodie}"
puts "Hold your horses... we are processing"

new_lines = []
File.open(foodie, "r ").each do |line|
  new_lines.push(line.split("|")[-1])
end

File.open(foodie, "w ") do |file|
  new_lines.each { |element| file.puts(element) }
end
  

Комментарии:

1. да, это вызывает ошибку. Я хочу удалить строку и заменить ее новой строкой (new_line)

2. @cyborg Я добавил / не очень элегантный / пример кода в свой ответ, дайте мне знать, если он выполнит работу 🙂