Извлечение значений из текстового тела в Ruby - PullRequest
3 голосов
/ 26 января 2011

Мне нужно извлечь некоторые значения из многострочной строки (которую я читаю из текста письма). Я хочу иметь возможность передавать шаблоны в свой синтаксический анализатор, чтобы позже можно было настраивать различные электронные письма. Я придумал следующее:

#!/usr/bin/env ruby

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

Name: Pepe Manuel Periquita

Email: pepe@manuel.net

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", "pepe@manuel.net", "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=>"pepe@manuel.net", :total=>6, :name=>"Pepe Manuel Periquita"}

Итак, я определяю шаблон как регулярное выражение в паре с блоком для построения хэша из совпадений. «Парсер» просто берет текст и применяет правила, выполняя блок в результате сопоставления регулярного выражения с текстом при сканировании.

В данный момент мне нужно проанализировать электронные письма в формате, как показано в text1, но позже я хотел бы как можно проще добавить шаблоны для извлечения данных из разных электронных писем (формат этих электронных писем будет фиксированным для каждого типа). Поэтому я бы хотел упростить перемещение шаблона в максимально возможной степени к «парсеру». Приведенный выше код работает и извлекает данные, но большая часть работы находится в шаблоне ...

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

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

Обновление

Я обновил синтаксический анализатор в соответствии с решением 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
}

1 Ответ

3 голосов
/ 26 января 2011

Может быть, что-то вроде этого достаточно универсально?

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=>"pepe@manuel.net"}
...