2011-01-26 2 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, но позже я хотел бы как можно проще добавить шаблоны для извлечения данных из разных электронных писем (формат этих писем будет исправлен для каждого типа) , Поэтому я хотел бы упростить шаблон, перемещающийся как можно больше к «парсеру». Вышеприведенный код работает и извлекает данные, но большая часть работы находится по шаблону ...

Это правильный путь?

Может быть упрощено или вы думаете о другом/лучшем решении этой проблемы?

Update

Я обновил парсер следующее решение 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