【问题标题】:private method `puts' called for "string":String (NoMethodError)为“字符串”调用私有方法“puts”:字符串(NoMethodError)
【发布时间】:2019-04-12 05:16:30
【问题描述】:

我正在使用 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)

【问题讨论】:

  • 我假设您知道对 Ruby v1.9.3 的支持已于四年多前(2015 年 2 月 23 日)结束。
  • 是的,不能强制行业更改版本:)

标签: ruby


【解决方案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#scanArray#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"

正则表达式的内容是,“将双引号后跟除管道 ("|") 之外的所有字符匹配到行尾”。每场比赛都将从该行最后一个管道后面的第一个双引号开始。

最后,将s 写回同一个文件,覆盖其内容。

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

看看吧。

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

IO::read 的使用有时被称为 gulping a file(作为字符串)。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 不知道有没有类似IO#write的使用词;可能将字符串放入文件中。尽管readwriteIO(类)方法,但它们通常在File 类中使用。没关系,因为File.superclass #=&gt; IO,所以File 继承了IO 的那些方法。

【讨论】:

  • 是的,我的文件非常大,有时 500 MB 到 1 GB。我正在尝试您的解决方案,遇到一些编码错误,我会修复它。
【解决方案2】:

此语句line.puts new_line 导致错误。

我假设您想要在这里实现的是将 new_line 写入输出文件,也许您认为 line 是一个 File 对象,但事实并非如此,因为 line 是一个 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

【讨论】:

  • 是的,这会导致错误。我想删除该行并将其替换为新字符串(new_line)
  • @cyborg 我在我的答案中添加了一个/不太优雅/示例代码,如果它完成了工作,请告诉我:)
猜你喜欢
  • 2014-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多