2011-08-28 51 views
1

好吧,我有这个ruby脚本,它打开一个文件,并将每行传递给line_parser方法。该方法只是简单地改变几个空格的选项卡。这是它:如何重构这个简单的Ruby算法

$lines = [] 

def line_parser(line) 
    line.gsub! /\t/, ' ' 
    $lines[$lines.length] = line 
end 

f = File.open(ARGV[0], 'r').each { |line| line_parser(line) } 
f.close 

f = File.open(ARGV[0], 'w') 
$lines.each { |line| f.puts line} 
f.close 

正如你可以看到它有两个循环; 一个循环迭代文件内的文本行,将它们放入数组中。而另一个循环再次将文件从最近创建的阵列中用新的线写入。

我的问题很简单,我认为: 我如何重构这段代码,这样我就只有一个循环内上述所有步骤?

我知道它可以做到,我只是无法用我目前的红宝石知识做到这一点。

在此先感谢!

+2

这个问题给出了一个替代:http://stackoverflow.com/questions/5452781/edit-each-line-in-a-file-in-ruby,这是写一个临时文件然后覆盖输入文件,而不是循环遍历行。虽然如果你只是寻找一个简单的方法来做到这一点(而不仅仅是一个更好的ruby方法),我相信'sed -i's/\ t// g'yourfile'会做到这一点。 – numbers1311407

+0

这种问题会更好,在http://codereview.stackexchange.com/ –

回答

2
out = "" 
File.open(ARGV[0], "r+") do |f| 
    f.each do |line| 
    out << line.gsub(/\t/, ' ') 
    end 
    f.pos=0 
    f.print out 
end 

这只是对文件迭代一次,但它仍然必须在文件最终写入文件之前缓存文件。如果你想避免缓存,你必须先写入临时文件。完成读取/写入操作后,您只需删除旧文件,并通过重命名将其替换为新的临时文件。

+0

你的代码工作得很好,比我所做的要好上百万倍。 :)但是,我只是想知道..可以做这个没有温度。文件或字符串或数组? (只是想知道..) – jlstr

2
#!/usr/local/bin/ruby -w 

src = File.read(ARGV[0]) 

File.open(ARGV[0], 'w') { | io | 
    src.each_line { | line | 
    io << line.gsub(/\t/, ' ') 
    } 
} 

请注意,这实际上是被骗了。读取整个文件实际上是一个循环。 但是,既然你正在阅读,然后写入同一个文件,我怀疑你可以避免有2个循环(一个用于阅读,一个用于书写)。

+0

看起来不错,非常地道。你能解释一下File.open块的io参数吗? 非常感谢您的回答! – jlstr

+0

@ user766388:这是用Ruby表示'io = File.open(...); io << ...; io.close'。 –

1

我们可以使用rubygems吗?

require 'rubygems' 
require 'facets/file' 

# Version 1 
File.write('outfile', File.read('infile').tr("\t", ' ')) 

# Version 2 
File.rewrite('inoutfile') { |str| str.tr("\t", ' ') } 
+0

我可以使用任何我想。这似乎是一个有趣的解决方案。 当我这样做时,我实际上将什么软件包拉到文件中:需要'rubygems'?请原谅我的无知。谢谢 – jlstr

+0

@user - Rubygems是ruby的事实上的包管理系统。当你需要rubygems时,你只需加载或激活包管理系统。完成后,可以使用'require'激活单个包,就像我在这里用'facets'包所做的那样。要了解更多信息并搜索或浏览可用的软件包,请访问:http://rubygems.org/ – Casper

+0

这对我来说非常有用。很好地解释,非常感谢你!我现在真的需要对这种语言有一点洞察力。 – jlstr