好吧,讓我們通過這方面的工作重複,從你的例子:
str = "2:README:19:string:Hello world!spec.rb:20:string:describe RBFS1:rbfs:4:0:0:"
entries = {} # No entries yet!
我們需要知道的第一件事情是多少文件有,而且我們知道,我們知道這是前第一數:
:
num_entries, rest = str.split(':', 2)
num_entries = Integer(num_entries)
# num_entries is now 2
# rest is now "README:19:string:Hello world!spec.rb:20:string:describe RBFS1:rbfs:4:0:0:"
的第二個參數split
說:「我只想要2個,」所以第一:
後停止分裂)我們用Integer(n)
而不是n.to_i
灣因爲它更嚴格。 (to_i
將轉換"10xyz"
到10
; Integer
會產生一個錯誤,這是我們想在這裏。)
現在我們知道我們有兩個文件。我們不知道別的還,但還剩下些什麼我們的字符串是這樣的:
README:19:string:Hello world!spec.rb:20:string:describe RBFS1:rbfs:4:0:0:
我們可以得到接下來的事情是名稱,第一個文件的長度。
name, len, rest = rest.split(':', 3)
len = Integer(len.to_i)
# name = "README"
# len = 19
# rest = "string:Hello world!spec.rb:20:string:describe RBFS1:rbfs:4:0:0:"
酷,現在我們的名字,第一個文件的長度,所以我們可以得到它的內容:
content = rest.slice!(0, len)
# content = "string:Hello world!"
# rest = "spec.rb:20:string:describe RBFS1:rbfs:4:0:0:"
entries[name] = content
# entries = { "README" => "string:Hello world!" }
我們使用rest.slice!
其修改從字符串前去除len
字符和返回它們,所以content
就是我們想要的(string:Hello world!
)而rest
就是它之後的所有東西。然後我們將其添加到entries
哈希。一個文件放下,一個去!
對於第二個文件,我們做同樣的事情:
name, len, rest = rest.split(':', 3)
len = Integer(len)
# name = "spec.rb"
# len = 20
# rest = "string:describe RBFS1:rbfs:4:0:0:"
content = rest.slice!(0, len)
# content = "string:describe RBFS"
# rest = "1:rbfs:4:0:0:"
entries[name] = content
# entries = { "README" => "string:Hello world!",
# "spec.rb" => "string:describe RBFS" }
因爲我們做同樣的事情兩次,顯然我們應該在一個循環做到這一點!但在寫這些之前,我們需要組織起來。到目前爲止,我們有兩個不連續的步驟:首先,獲取文件的數量。其次,獲取這些文件的內容。我們也知道我們需要獲取目錄和目錄的數量。我們將在如何將看看猜一猜:
def parse(serialized)
files, rest = parse_files(serialized)
# `files` will be a Hash of file names and their contents and `rest` will be
# the part of the string we haven't serialized yet
directories, rest = parse_directories(rest)
# `directories` will be a Hash of directory names and their contents
files.merge(directories)
end
def parse_files(serialized)
# Get the number of files from the beginning of the string
num_entries, rest = str.split(':', 2)
num_entries = Integer(num_entries)
entries = {}
# `rest` now starts with the first file (e.g. "README:19:...")
num_entries.times do
name, len, rest = rest.split(':', 3) # get the file name and length
len = Integer(len)
content = rest.slice!(0, len) # get the file contents from the beginning of the string
entries[name] = content # add it to the hash
end
[ entries, rest ]
end
def parse_directories(serialized)
# TBD...
end
這parse_files
方法是有點長對我的口味,雖然如此,我們怎麼辦分裂它?
def parse_files(serialized)
# Get the number of files from the beginning of the string
num_entries, rest = str.split(':', 2)
num_entries = Integer(num_entries)
entries = {}
# `rest` now starts with the first file (e.g. "README:19:...")
num_entries.times do
name, content, rest = parse_file(rest)
entries[name] = content # add it to the hash
end
[ entries, rest ]
end
def parse_file(serialized)
name, len, rest = serialized.split(':', 3) # get the name and length of the file
len = Integer(len)
content = rest.slice!(0, len) # use the length to get its contents
[ name, content, rest ]
end
乾淨!
現在,我打算給你一個大搗蛋者:由於序列化格式設計合理,我們實際上並不需要parse_directories
方法,因爲它的做法與parse_files
完全相同。該唯一不同的是,此行之後:
name, content, rest = parse_file(rest)
...我們想,如果我們解析目錄,而不是文件做不同的事情。特別是,我們打電話給parse(content)
,這將在目錄的內容上完成所有這些。既然它現在正在推行雙重任務,我們可能應該將其名稱更改爲更通用的名稱,例如parse_entries
,並且我們還需要提供另一個參數來告訴它何時執行該遞歸。
與其在此處發佈更多代碼,我已發佈我的「已完成」產品over in this Gist。
現在,我知道這對serialize
部分沒有幫助,但希望它能幫助您入門。 serialize
是比較容易的部分,因爲關於在遞歸迭代哈希上有很多問題和答案。
您可以舉一個稍微複雜的目錄結構的序列化例子,例如多個非空兄弟目錄? – 2014-10-31 22:27:41