我有一個包含用空行分隔文本塊文件,像這樣:如何讀取文件的段落或塊成陣列
block 1
some text
some text
block 2
some text
some text
我怎麼能閱讀到一個數組?
我有一個包含用空行分隔文本塊文件,像這樣:如何讀取文件的段落或塊成陣列
block 1
some text
some text
block 2
some text
some text
我怎麼能閱讀到一個數組?
這要求往往不夠,我想那會解釋做什麼有用的,但首先我需要這樣說:
不要試圖讀取一個大口的文件。這就是所謂的「啜泣」,除非你能保證你總能獲得明顯小於1MB的文件,否則這是一個壞主意。有關更多信息,請參閱「Why is "slurping" a file not a good practice?」。
如果我有,看起來像一個文件:
block 1
some text
some text
block 2
some text
some text
,我試圖正常讀取它,我會得到這樣的:
File.read('foo.txt')
#=> "block 1\nsome text\nsome text\n\nblock 2\nsome text\nsome text\n"
這會使我不得不把它分解分成單獨的行,試圖找到空行,然後將其分成塊。總而言之,天真的解決方案是使用正則表達式,這種正則表達式可以工作,但不是最優的。
或者我們可以嘗試:
File.readlines('foo.txt')
#=> ["block 1\n", "some text\n", "some text\n", "\n", "block 2\n", "some text\n", "some text\n"]
之後,還必須找到空行,並打開陣列分爲子陣列。
相反,有兩種簡單的方法來加載文件。
牢記約啜文件,如果它是一個小文件,我們可以使用以前的警告:
File.readlines('foo.txt', "\n\n")
#=> ["block 1\nsome text\nsome text\n\n", "block 2\nsome text\nsome text\n"]
請注意,在第二個參數使用"\n\n"
。這就是「行分隔符」,它通常被定義爲* nix類型操作系統的「\ n」和Windows的「\ r \ n」。它實際上是基於Ruby衍生的全球價值,它親切地稱爲$/
,$RS
或$INPUT_RECORD_SEPARATOR
。它們記錄在English模塊中。記錄分隔符是在文本文件中用來分隔兩行的字符,或者,對於我們的目的而言,是由兩個行尾字符或換句話說,一個段落分隔的一組行。
讀取一次,很容易清理的內容刪除尾隨線兩端:
File.readlines('foo.txt', "\n\n").map(&:rstrip)
#=> ["block 1\nsome text\nsome text", "block 2\nsome text\nsome text"]
或將其分解成子陣列:可用於
File.readlines('foo.txt', "\n\n").map{ |s| s.rstrip.split("\n") }
#=> [["block 1", "some text", "some text"], ["block 2", "some text", "some text"]]
所有的例子具有類似於一個段落:
File.readlines('foo.txt', "\n\n").map(&:rstrip).each do |line|
# do something with line
end
或:
File.readlines('foo.txt', "\n\n").map{ |s| s.rstrip.split("\n") }.each do |paragraph|
# do something with the sub-array `paragraph`
end
如果它是一個大的文件,我們可以通過foreach
使用Ruby的行由行IO如果文件尚未打開,或者each_line
如果它是一個已打開的文件。而且,由於您閱讀了上面的鏈接,您已經知道我們爲什麼要使用逐行IO。
File.foreach('foo.txt', "\n\n") #=> #<Enumerator: File:foreach("foo.txt", "\n\n")>
foreach
返回一個枚舉,所以我們需要釘在to_a
閱讀陣列,所以我們可以看到的結果,但通常我們會不會有這樣做:
File.foreach('foo.txt', "\n\n").to_a
#=> ["block 1\nsome text\nsome text\n\n", "block 2\nsome text\nsome text\n"]
這很容易使用foreach
像上面:
File.foreach('foo.txt', "\n\n").map(&:rstrip)
#=> ["block 1\nsome text\nsome text", "block 2\nsome text\nsome text"]
File.foreach('foo.txt', "\n\n").map(&:rstrip).map{ |s| s.rstrip.split("\n") }
#=> [["block 1", "some text", "some text"], ["block 2", "some text", "some text"]]
注:我強烈懷疑使用map
這樣會造成simil因爲Ruby在傳遞給map
之前會緩存foreach
的輸出。相反,我們需要做的do
塊讀取裏面的每個段落的操作:
File.foreach('foo.txt', "\n\n") do |ary|
ary.rstrip.split("\n").each do |line|
# do something with the individual line
end
end
這樣做是小命中在性能,但是,因爲我們的目標是通過段或塊來處理,這是可以接受的。
另請注意,這是一個社區Wiki,所以請編輯並作出適當的貢獻。