#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 Я добавил / не очень элегантный / пример кода в свой ответ, дайте мне знать, если он выполнит работу 🙂