2011-08-28 50 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