2012-08-07 85 views
0

我必須在Ruby中從文件模式中刪除一些線條。例如,我有一個文件是這樣的:在ruby模式後刪除線條

# pattern 1 
a 
b 
# end pattern 1 
# pattern 2 
a 
b 
c 
d 
# end pattern 2 
# pattern 3 
a 
b 
c 
# end pattern 3 

我想刪除# pattern 2# end pattern 2之間的界線。
,我希望得到的文件是:

# pattern 1 
a 
b 
# end pattern 1 
# pattern 3 
a 
b 
c 
# end pattern 3 
+0

我試着在紅寶石GSUB,但只能刪除/替換單行,而不是一個文本塊。我搜查了,但我找不到適合這項任務的任何東西。 – pfrancesco 2012-08-07 14:48:02

+0

請顯示你寫的代碼。我們寧願告訴你出錯的地方,而不是爲你寫一個完整的解決方案。 – 2012-08-07 17:39:12

+0

您正在處理的文件有多大?如果它是合理的大小,那將適合內存,使用'File.read()'將其完全拉入,然後單個'gsub()'將允許您去除目標線條,然後將結果寫入新文件。請參閱以下有關做文件更改的評論。 – 2012-08-07 17:45:50

回答

0

你可以用String#gsub做,但你需要傳遞一個選項,正則表達式,這將使點匹配換行符。

str = <<-STR 
# pattern 1 
a 
b 
# end pattern 1 
# pattern 2 
a 
b 
c 
d 
# end pattern 2 
# pattern 3 
a 
b 
c 
# end pattern 3 
STR 

puts str.gsub(/(# pattern 2.*# end pattern 2\n)/m, '') 
# >> # pattern 1 
# >> a 
# >> b 
# >> # end pattern 1 
# >> # pattern 3 
# >> a 
# >> b 
# >> c 
# >> # end pattern 3 
+0

感謝它的工作,但我可以直接寫入文件嗎?使用'file = File.open(「/ etc/file」,「rb」)'和'content = file.read'我可以把文件的內容放到一個字符串中,但是我想直接在文件中工作, 那可能嗎? – pfrancesco 2012-08-07 15:51:35

+0

是的,這是可能的,但是您將無法使用正則表達式。 – 2012-08-07 15:55:18

+0

@pfrancesco,出於數據完整性的原因,直接在文件中工作並不是建議的做法。如果您的代碼在此過程中失敗,那麼您的數據文件將被損壞,並且很可能不會輕易恢復。閱讀原件並寫入新版本,然後將原件重命名爲其他內容,然後將新版本重命名爲原件名稱會更好。然後您可以自由刪除原始文件。 – 2012-08-07 17:43:09

0

我喜歡避免使用正則表達式,除非他們真的有必要。在這種情況下,他們不是。只需逐行掃描每行即可。當看到「#pattern 2」時檢測並停止打印行。當您看到「#結束樣式2」並再次開始打印行時檢測。這可以用一個本地布爾變量很容易地完成,你應該自己做一個練習,因爲它聽起來像你對Ruby不太瞭解,不知道該怎麼嘗試。

有在Ruby中一個很酷的技巧,使變量不必要的:在這裏,文件的

str = <<END 
X 
# pattern 2 
Y 
Z 
# end pattern 2 
Q 
END 

str.split("\n").each do |line| 
    puts line unless (line=="# pattern 2")..(line=="# end pattern 2") 
end 
+0

由於'#'它不起作用,這是一條評論。順便說一下,這不是問題,我試圖讓它與文件一起工作 – pfrancesco 2012-08-07 17:55:32

+0

'#'字符在字符串中沒有特殊含義。我在Ruby 1.9.3上運行了上面的代碼,它產生了所需的輸出。它爲你產生了什麼樣的輸出,以及你嘗試使用哪種版本的紅寶石? 「它不起作用」是什麼意思? – 2012-08-08 06:38:34

0

愛招,但如果你想直接處理文件,這裏是另一種解決方案,發揮POS機和退(抱歉,沒有異常處理文件IO):

def gsub_paragraph(options) 
    regex_start = /^.*#{options[:pattern_start]}.*$/ 
    regex_stop = /^.*#{options[:pattern_stop]}.*$/ 

    f_read = File.new(options[:file_in], 'r') 
    true until (line_pattern = regex_start.match(f_read.gets)) 
    pos_start = f_read.pos - line_pattern[0].length - 1 
    f_read.rewind 
    part_start = f_read.read(pos_start) 

    true until (line_pattern = regex_stop.match(f_read.gets)) 
    pos_stop = f_read.pos 
    part_stop = f_read.read(pos_stop) 
    f_read.close 

    f_write = File.new((options[:file_out] || options[:file_in]), 'w+') 
    replacement = options[:replacement] || '' 
    f_write.puts part_start + replacement + part_stop 
    f_write.close 
end 


file = "gsub_in.txt" 

# Output to a designated file other than source file, replace matched part 
gsub_paragraph(:file_in => file, :pattern_start => 'pattern 2', :pattern_stop => 'end pattern 2', :replacement => "~~~I replaced sth here~~~\n", :file_out => 'gsub_out.txt') 

# Output to a designated file other than source file, without replacement 
gsub_paragraph(:file_in => file, :pattern_start => 'pattern 2', :pattern_stop => 'end pattern 2', :file_out => 'gsub_out.txt') 

# Output to source file directly, without replacement 
gsub_paragraph(:file_in => file, :pattern_start => 'pattern 2', :pattern_stop => 'end pattern 2')