2011-01-26 30 views
3

我需要从多行字符串(我从电子邮件的文本正文中读取)中提取一些值。我希望能够将模式提供给解析器,以便稍后可以自定义不同的电子邮件。我想出了以下情况:从Ruby中的文本正文中提取值

#!/usr/bin/env ruby 

text1 = 
<<-eos 
Lorem ipsum dolor sit amet, 

Name: Pepe Manuel Periquita 

Email: [email protected] 

Sisters: 1 
Brothers: 3 
Children: 2 

Lorem ipsum dolor sit amet 
eos 

pattern1 = { 
    :exp => /Name:[\s]*(.*?)$\s* 
      Email:[\s]*(.*?)$\s* 
      Sisters:[\s]*(.*?)$\s* 
      Brothers:[\s]*(.*?)$\s* 
      Children:[\s]*(.*?)$/mx, 
    :blk => lambda do |m| 
    m.flatten! 
    {:name => m[0], 
    :email => m[1], 
    :total => m.drop(2).inject(0){|sum,item| sum + item.to_i}} 
    end 
} 

# Scan on text returns 
#[["Pepe Manuel Periquita", "[email protected]", "1", "3", "2"]] 

    def do_parse text, pattern 
    data = pattern[:blk].call(text.scan(pattern[:exp])) 

    puts data.inspect 
    end 


do_parse text1, pattern1 

# ./text_parser.rb 
# {:email=>"[email protected]", :total=>6, :name=>"Pepe Manuel Periquita"} 

所以,我定义的图案与块从比赛建立一个哈希配对的正则表达式。 “解析器”只是简单地使用文本并通过对正则表达式与扫描的文本匹配的结果执行块来应用规则。

目前我不得不解析邮件格式如文本1所示,但后来我想尽可能方便地添加模式从不同的电子邮件中提取数据(这些电子邮件的格式将为每种类型固定) 。因此,我想简化模式,尽可能移动到“解析器”。上面的代码工作并提取数据,但大部分工作位于该模式...

这是正确的路要走吗?

可能会被简化或您认为针对此问题的不同/更好的解决方案?

更新

我更新了以下Tonttu解决方案分析器所以图案散列现在是:

pattern2 = { 
    :exp => /^(.+?):\s*(.+)$/, 
    :blk => lambda do |m| 
    r = Hash[m.map{|x| [x[0].downcase.to_sym, x[1]]}] 

    {:name => r[:name], 
    :email => r[:email], 
    :total => r[:children].to_i + r[:brothers].to_i + r[:sisters].to_i} 
    end 
} 

回答

3

也许这样的事情是通用的?

pp Hash[*text1.scan(/^(.+?):\s(.+)$/).map{|x| 
    [x[0].downcase.to_sym, x[1]] 
    }.flatten] 

=> 
{:sisters=>"1", 
:brothers=>"3", 
:children=>"2", 
:name=>"Pepe Manuel Periquita", 
:email=>"[email protected]"} 
+0

这是非常好的,但你将如何应用匹配值的表达式来派生其他值,如我的例子中的总数是三个字段的总和? – Miquel 2011-01-26 10:24:16