2015-08-25 56 views
1

我使用Parslet解析一些自定義的數據開始。在這些例子中,所產生的解析數據是一樣的東西:如何使用Parslet用繩子不Parslet片

{ :custom_string => "data"@6 } 

而且我創建的轉換像

rule(:custom_string => simple(:x)) { x.to_s } 

但它不匹配,大概是因爲我傳遞「數據「@ 6而不僅僅是」數據「,這不僅僅是一個簡單的字符串。所有examples的變換有哈希值與字符串,而不是與Parslet ::片是什麼解析器輸出。也許我錯過了一個步驟,但我無法看到文檔中的任何內容。

編輯:更多的示例代碼(縮版但仍應該說明)

original_text = 'MSGSTART/DATA1/DATA2/0503/MAR' 

require "parslet" 
include Parslet 

module ParseExample 
    class Parser < Parslet::Parser 
    rule(:fs)   { str("/") } 
    rule(:newline) { str("\n") | str("\r\n") } 

    rule(:msgstart) { str("MSGSTART") } 
    rule(:data1) { match("\\w").repeat(1).as(:data1) } 
    rule(:data2) { match("\\w").repeat(1).as(:data2) } 
    rule(:serial_number) { match("\\w").repeat(1).as(:serial_number) } 
    rule(:month) { match("\\w").repeat(1).as(:month) } 

    rule(:first_line) { msgstart >> fs >> data1 >> fs >> data2 >> fs >> serial_number >> fs >> month >> newline } 

    rule(:document) { first_line >> newline.maybe } 

    root(:document) 
    end 
end 

module ParseExample 
    class Transformer < Parslet::Transform 

    rule(:data1 => simple(:x)) { x.to_s } 
    rule(:data2 => simple(:x)) { x.to_s } 
    rule(:serial_number => simple(:x)) { x.to_s } 
    rule(:month => simple(:x)) { x.to_s } 
    end 
end 

# Run by calling... 
p = ParseExample::Parser.new 
parse_result = p.parse(original_text) 

# => {:data1=>"data1"@6, :data2=>"data2"@12, :serial_number=>"0503"@18, :month=>"MAR"@23} 

t = ParseExample::Transformer.new 
transformed = t.apply(parser_result) 

# Actual result => {:data1=>"data1"@6, :data2=>"data2"@12, :serial_number=>"0503"@18, :month=>"MAR"@23} 

# Expected result => {:data1=>"data1", :data2=>"data2", :serial_number=>"0503", :month=>"MAR"} 
+0

變形金剛既散列和對象樹工作從解析器返回。所以別的東西一定是錯的。請張貼更多的代碼,以便我們發現問題。 –

回答

2

不能替換單個鍵/值對。您必須立即替換整個散列。

我愛上了這個第一次我寫了變壓器過。關鍵在於轉換規則匹配整個節點並將其替換爲純粹的。一旦節點匹配,它不會再次訪問。

如果沒有消費的哈希,只匹配單個鍵/值對,用一個值取代它......你只是失去了所有其他的鍵/值對在相同的散列。

不過......有一個辦法!

如果您希望在匹配整個散列之前預先處理散列中的所有節點,則散列值必須是散列本身。然後你可以匹配這些並將它們轉換爲字符串。你通常可以通過簡單地在你的解析器添加另一「爲」做到這一點。

例如:

original_text = 'MSGSTART/DATA1/DATA2/0503/MAR' 

require "parslet" 
include Parslet 

module ParseExample 
    class Parser < Parslet::Parser 
    rule(:fs)   { str("/") } 
    rule(:newline) { str("\n") | str("\r\n") } 

    rule(:msgstart) { str("MSGSTART") } 

    rule(:string) {match("\\w").repeat(1).as(:string)} # Notice the as! 

    rule(:data1) { string.as(:data1) } 
    rule(:data2) { string.as(:data2) } 
    rule(:serial_number) { string.as(:serial_number) } 
    rule(:month) { string.as(:month) } 

    rule(:first_line) { 
     msgstart >> fs >> 
     data1 >> fs >> 
     data2 >> fs >> 
     serial_number >> fs >> 
     month >> newline.maybe 
    } 

    rule(:document) { first_line >> newline.maybe } 

    root(:document) 
    end 
end 

# Run by calling... 
p = ParseExample::Parser.new 
parser_result = p.parse(original_text) 

puts parser_result.inspect 
# => {:data1=>{:string=>"DATA1"@9}, 
     :data2=>{:string=>"DATA2"@15}, 
     :serial_number=>{:string=>"0503"@21}, 
     :month=>{:string=>"MAR"@26}} 

# See how the values in the hash are now all hashes themselves. 

module ParseExample 
    class Transformer < Parslet::Transform 
    rule(:string => simple(:x)) { x.to_s } 
    end 
end 

# We just need to match the "{:string => x}" hashes now...and replace them with strings 

t = ParseExample::Transformer.new 
transformed = t.apply(parser_result) 

puts transformed.inspect 
# => {:data1=>"DATA1", :data2=>"DATA2", :serial_number=>"0503", :month=>"MAR"} 

# Tada!!! 

如果你本來想辦理整條生產線,做從它創建一個對象..說..

class Entry 
    def initialize(data1:, data2:, serial_number:,month:) 
     @data1 = data1 
     @data2 = data2 
     @serial_number = serial_number 
     @month = month 
    end 
end 

module ParseExample 
    class Transformer < Parslet::Transform 
    rule(:string => simple(:x)) { x.to_s } 

    # match the whole hash 
    rule(:data1 => simple(:d1), 
     :data2 => simple(:d2), 
     :serial_number => simple(:s), 
     :month => simple(:m)) { 
      Entry.new(data1: d1,data2: d2,serial_number: s,month: m)} 
    end 
end 

t = ParseExample::Transformer.new 
transformed = t.apply(parser_result) 

puts transformed.inspect 
# => #<Entry:0x007fd5a3d26bf0 @data1="DATA1", @data2="DATA2", @serial_number="0503", @month="MAR"> 
+0

感謝Nigel的巨大幫助。這很有用。 – Simmo