2013-01-11 38 views
0

我想將此字符串文本轉換爲基於用戶輸入創建頁面的散列。將文本解析爲二維散列

Home 
About 
- News 
-- Local News 
-- Global News 
- Who We Are 
Product 

這只是一個例子,但我想將它轉換爲我可以遍歷的多維散列。我想創建一個簡單的方式讓用戶在CMS中創建頁面。

我玩過分裂字符串和正則表達式,但我還沒有走過。

任何幫助將不勝感激!

+3

顯示您嘗試過的一些代碼。 –

+0

什麼是多維散列? – sawa

+0

@sawa這是一個哈希值,它具有其他哈希值。嵌套散列是它的另一個術語。你可以在下面的答案中看到示例(方法的輸出) – plasticide

回答

0

這是我的嘗試。我完全承認它看起來不太習慣,並且在ruby stdlib中可能會有一行代碼可以替代它。但是,嘿,至少這個工程:)

所以,基本的思路是這樣的:

  • 休息文字單獨的行
  • 迭代此線陣列,並逐步構建hash。保持跟蹤「當前節點」,而你這樣做
  • 如果此行有更多的「 - 」字符,那麼前一個,那麼這行必須是以前
  • 孩子等

代碼:

txt = <<-TXT 
Home 
About 
- News 
-- Local News 
-- Global News 
- Who We Are 
Product 
TXT 

def lines_to_hash lines 
    res = {} 
    last_level = 0 
    parent_stack = [res] 
    last_line = nil 

    lines.each do |line| 
    cur_level = line.scan('-').length 
    if cur_level > last_level 
     parent_stack << parent_stack.last[last_line] 
    elsif cur_level < last_level 
     parent_stack.pop 
    end 

    clean_line = line.gsub(/^[-\s]+/, '') 
    parent_stack.last[clean_line] = {} 
    last_line = clean_line 
    last_level = cur_level 
    end 
    res 
end 

res = lines_to_hash(txt.split("\n")) 
res # => {"Home"=>{}, 
    #  "About"=>{"News"=>{"Local News"=>{}, "Global News"=>{}}, 
    #    "Who We Are"=>{}}, 
    #  "Product"=>{}} 

如果有人想出了一個俏皮話,我會獎勵+100代表在賞金:)

+0

[Challenge accepted!](http://stackoverflow.com/questions/14280573/parsing-text-into-dimensional-hash/14282912#14282912) –

2

看起來YAML會成爲你的朋友。看看Yaml.load。 test.yml:

"Home": 
    "About": 
    "News": 
     "Local News": 
     "Global News": 
     "Who We Are": 
    "Products": 

IRB

require 'yaml' 
YAML.load(File.open('test.yml')) 
=> {"home"=>{"About"=>{"News"=>{"Local News"=>nil, "Global News"=>nil, "Who We Are"=>nil}}, "Product"=>nil}} 
+1

只想添加:如果你想做一個解析器你可以看看[Parslet](http://kschiess.github.com/parslet/) –

+0

這看起來像一個很酷的圖書館! – plasticide

+1

由於[Rails剛剛發現](http://blog.codeclimate.com/blog/2013/01/10/rails-remote-code-execution-vulnerability-explained/),如果你想要非常小心'要去'YAML.load'任何用戶可編輯的! –

0
txt = <<-TXT 
Home 
About 
- News 
-- Local News 
-- Global News 
- Who We Are 
Product 
TXT 

def hashify s 
    Hash[s.split(/^(?!-)\s*(.*)/).drop(1).each_slice(2).map{|k, v| [k, hashify(v.to_s.strip.gsub(/^-/, ""))]}] 
end 

hashify(txt) 
# => 
# { 
# "Home" => {}, 
# "About" => { 
#  "News"  => { 
#  "Local News" => {}, 
#  "Global News" => {} 
#  }, 
#  "Who We Are" => {} 
# }, 
# "Product" => {} 
# } 
0

@Sergio:這是一個一行! (誠​​然,我已經把它分割到幾個線「清晰度」)

@ LT-matt8:如果你確實使用此然後,我要爲未來的人的理智概不負責稍後閱讀你的代碼:)

text = <<-TEXT 
Home 
About 
- News 
-- Local News 
-- Global News 
- Who We Are 
Product 
TEXT 

hash = text.lines.each_with_object([{}]) {|item, levels| 
    item.match(/(-*)\s*(.*)/).captures.tap {|level, title| 
    levels[level.size][title] = (levels[level.size + 1] = {}) 
    } 
}.first 
# => {"Home"=>{}, "About"=>{"News"=>{"Local News"=>{}, "Global News"=>{}}, "Who We Are"=>{}}, "Product"=>{}} 
+0

雖然您的答案在技術上符合條件,但@ sawa的答案更短。他的職位更老了。 –

+0

無論如何,我將不得不等待2天才能開始賞金。 –

+0

哦同意了,@ sawa的好多了。我只是試圖在沒有遞歸的情況下做到這一點 - 如果你必須定義一個方法,它在技術上仍然是一個單線程? ;) –