正则表达式解析iCalendar(Ruby正则表达式)

时间:2012-10-26 22:31:14

标签: ruby regex icalendar rfc2445 rfc5545

我正在尝试使用正则表达式解析iCalendar(RFC2445)输入。

这是输入内容的[简化]示例:

BEGIN:VEVENT
abc:123
def:456
END:VEVENT
BEGIN:VEVENT
ghi:789
END:VEVENT

我想获得一系列匹配:“外部”匹配是每个VEVENT块,内部匹配是每个字段:值对。

我尝试过这个变种:

BEGIN:VEVENT\n((?<field>(?<name>\S+):\s*(?<value>\S+)\n)+?)END:VEVENT

但是考虑到上面的输入,结果似乎每个匹配的VEVENT只有一个字段,尽管+?捕获组:

**Match 1**
field   def:456
name    def
value   456

**Match 2**
field   ghi:789
name    ghi
value   789

在第一场比赛中,我预计会有两个领域:abc:123和def:456匹配......

我确定这是一个新手的错误(因为我似乎永远是一个新手,当谈到正则表达式......) - 但也许你可以指出我正确的方向?

谢谢!

5 个答案:

答案 0 :(得分:2)

使用icalendar gem。 有关详细信息,请参阅Parsing iCalendars部分。

答案 1 :(得分:1)

您需要嵌套scan

string.scan(/^BEGIN:VEVENT\n(.*?)\nEND:VEVENT$/m).each.with_index do |item, i|
  puts
  puts "**Match #{i+1}**"
  item.first.scan(/^(.*?):(.*)$/) do |k, v|
    puts "field".ljust(7)+"#{k}:#{v}"
    puts "name".ljust(7)+"#{k}"
    puts "value".ljust(7)+"#{v}"
  end
end

会给:

**Match 1**
field   abc:123
name    abc
value   123
field   def:456
name    def
value   456

**Match 2**
field   ghi:789
name    ghi
value   789

答案 2 :(得分:1)

您需要将正则表达式拆分为一个匹配的VEVENT和一个匹配名称/值对。然后,您可以使用嵌套的scan来查找所有出现的事件,例如: G。

str.scan(/BEGIN:VEVENT((?<vevent>.+?))END:VEVENT/m) do
  $~[:vevent].scan(/(?<field>(?<name>\S+?):\s*(?<value>\S+?))/) do
    p $~[:field], $~[:name], $~[:value]
  end
end

其中str是您的输入。这输出:

"abc:1"
"abc"
"1"
"def:4"
"def"
"4"
"ghi:7"
"ghi"
"7"

如果您想让代码更具可读性,建议您require 'english'并将$~替换为$LAST_MATCH_INFO

答案 3 :(得分:0)

我认为问题是ruby MatchData对象(regexp返回其结果)没有为多个具有相同名称的值提供任何规定。所以你的第二场比赛将覆盖第一场比赛。

答案 4 :(得分:0)

Ruby有一种很少使用的名为slice_before的方法,可以很好地满足这个需求:

'BEGIN:VEVENT
abc:123
def:456
END:VEVENT
BEGIN:VEVENT
ghi:789
END:VEVENT'.split("\n").slice_before(/^BEGIN:VEVENT/).to_a

结果:

[["BEGIN:VEVENT", "abc:123", "def:456", "END:VEVENT"],
 ["BEGIN:VEVENT", "ghi:789", "END:VEVENT"]]    

从那里抓住内部数组元素很简单:

'BEGIN:VEVENT
abc:123
def:456
END:VEVENT
BEGIN:VEVENT
ghi:789
END:VEVENT'.split("\n").slice_before(/^BEGIN:VEVENT/).map{ |a| a[1 .. -2] }

这是:

[["abc:123", "def:456"], ["ghi:789"]]

而且,从那里使用mapsplit(':')分解每个结果字符串是微不足道的。

不要被试图做任何事情的正则表达式的警笛声所诱惑。它们在特定的地方非常强大和方便,但通常有更简单,更容易维护的解决方案。