寻找有关如何匹配模式的想法,可能与否?

时间:2010-11-18 17:41:34

标签: ruby-on-rails ruby regex

我正在寻找帮助创建模式匹配来摄取电子邮件。最终目标是接收传入消息并仅提取回复消息,而不是所有尾随垃圾(先前的线程,签名,数据队列标题等)

以下是两种相同的格式:

格式1:

The Message is here, etc etc can span a random # of lines

On Nov 17, 2010, at 4:18 PM, Person Name wrote:

lots of junk down here which we don't want

格式2:

The Message is here, etc etc can span a random # of lines

On Nov 17, 2010, at 4:18 PM, Site <yadaaaa+adad@sitename.com> wrote:

lots of junk down here which we don't want

格式3:

The Message is here, etc etc can span a random # of lines

On Fri, Nov 19, 2010 at 1:57 AM, <customerserviceonline@pge.com> wrote:

lots of junk down here which we don't want

对于上面的两个例子,我想创建一个模式匹配,找到第二行的第一个实例。然后只返回该行以上的内容。我不想要那个分隔线。

我无法在日期戳上匹配,但我可以匹配逗号之后的所有内容,因为这是我的控制。

所以这个想法,寻找这两个静态项中的任何一个:

, Site <yadaaaa+adad@sitename.com> wrote:
, Person Name wrote:

然后把一切都放在那个位置之上。你怎么看。这可能吗?

3 个答案:

答案 0 :(得分:2)

我会添加一种不同的方法:为什么你不读取所有内容并在匹配你停止的行时中断?

答案 1 :(得分:1)

如果您尝试在一个模式中完成所有操作,这对正则表达式来说不是很好用。这是可能的,但我怀疑在你解决所有错误之前宇宙会变凉。

要了解您尝试执行的操作范围,请阅读Wikipedia's article on "Posting Style"。回复嵌入到电子邮件中的方式有​​很多种,部分由MUA(邮件用户代理)控制,部分由执行回复的人控制。没有设置归属的方法,也没有规则说回复在页面上的一个块中,或者它位于页面的顶部。这意味着您编写的任何代码都必须非常复杂才能有可能始终如一地工作。

你看过Mail了吗?它已经写好了,经过了很好的测试,它有各种各样的酷炫的口哨声,它已经写好了。 (我再说一遍,因为重新发明效果很好的车轮会非常痛苦。)

解析纯文本电子邮件是一项任务。然后是MIME编码的电子邮件,具有不同的内容类型。然后有“HTML”电子邮件,没有MIME块,但一些白痴只是想到每个人都喜欢HTML格式和闪烁文本。然后是各种奇怪破碎的消息体类型,其中包含四种回复引用类型,并且所有先前消息的全部内容都在下一个附加,并且包含我最喜欢的书的整个文本的非常沮丧的想成为作者的签名“抓住的女孩“,AKA Vol。不列颠百科全书5。 Mail可以帮助您清除所有垃圾,为您提供所需内容。

要获取正文中的一系列文本,请查看Ruby的..(AKA“触发器”)运算符。它设计为在发生两个不同的测试时返回布尔值true / false。请参阅“When would a Ruby flip-flop be useful?

通常你会像以下一样构建它:

if ((string =~ /pattern1/) .. (string =~ /pattern2/))
    ...
end

当处理发生时,如果第一个测试匹配某个东西,那么后续循环将落入if块。当找到结束测试时,将关闭该块以用于后续循环。在这种情况下,您需要使用字符串文字或小型正则表达式来定位起始行和结束行。如果您有机会在后面的文本中看到起始模式,那么您将不得不弄清楚如何捕获它。

例如,如果某人做了最高回复,这里有一种方法可以获取一些看似满足您声明要求的内容:

msg = <<EOT
The Message is here, etc etc can span a random # of lines
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod

On Nov 17, 2010, at 4:18 PM, Person Name wrote:

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
EOT

body = []
msg.lines.each do |li|
  li.chomp!
  body << li
  break if (li =~ /^On (\S+ )*\w+ \d+, \d+, at [\d:]+ \w+, .+ wrote:/i)
end
puts body[0 .. -2]

puts '=' * 40

msg = <<EOT
The Message is here, etc etc can span a random # of lines
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod

On Nov 17, 2010, at 4:18 PM, Site <yadaaaa+adad@sitename.com> wrote:

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
EOT

body = []
msg.lines.each do |li|
  li.chomp!
  body << li
  break if (li =~ /^On (\S+ )*\w+ \d+, \d+, at [\d:]+ \w+, .+ wrote:/i)
end
puts body[0 .. -2]

这是输出:

# >> The Message is here, etc etc can span a random # of lines
# >> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
# >> 
# >> ========================================
# >> The Message is here, etc etc can span a random # of lines
# >> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
# >> 

模式可能更简单,但如果是这样会增加返回误报的机会。

答案 2 :(得分:1)

那么这将是一个正则表达式解决方案:

/(On (?:(?:Sun|Mon|Tues|Wed|Thurs|Fri|Sat), |)(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \d{1,2}, [12]\d{3}(?:|,) at \d{1,2}:\d{1,2} (?:AM|PM), (?:(?:Site |)<[\w.%+-]+@[\w.-]+\.[A-Za-z]{2,4}>|Person \w+) wrote:)/

你刚提供了一个例子,所以这可能不完美,但它应该做得很好。

然后,如果您使用匹配,则必须使用$ 1或[0]获取第一个捕获的组:)

regex =  /(On (?:(?:Sun|Mon|Tues|Wed|Thurs|Fri|Sat), |)(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \d{1,2}, [12]\d{3}(?:|,) at \d{1,2}:\d{1,2} (?:AM|PM), (?:(?:Site |)<[\w.%+-]+@[\w.-]+\.[A-Za-z]{2,4}>|Person \w+) wrote:)/

if str =~ regex
  puts "S1 : #{$1}"
end

if res = str.match(regex)
  puts "S2 : #{res[0]}"
end

顺便说一句,您可以在正则表达式上使用选项/i