iCalendar的正则解析(Ruby Regex)



我正在尝试使用正则分析iCalendar(RFC2445)输入。

这是输入的样子的[简化]示例:

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

我想获得一系列匹配:"外部"匹配是每个障碍块,内部匹配是每个字段:值对。

我尝试过的变体:

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

但是给出了上面的输入,尽管 ?在捕获组上:

**Match 1**
field   def:456
name    def
value   456
**Match 2**
field   ghi:789
name    ghi
value   789

在第一场比赛中,我本来可以期待两个领域:ABC:123和DEF:456匹配...

我敢肯定这是一个新手错误(因为我似乎永远是新手,而Regex的...) - 但也许您可以指向正确的方向?

谢谢!

您需要将正则拨号拆分为一个匹配的 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

替换$~

使用iCalendar Gem。有关更多信息,请参见"解析ICICARENDARS"部分。

您需要一个嵌套的scan

string.scan(/^BEGIN:VEVENTn(.*?)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

我认为问题是Ruby MatchData对象(Regexp返回其结果)没有任何一个以上值的规定,具有相同名称。因此,您的第二场比赛覆盖了第一个。

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(':')分解每个结果字符串是微不足道的。

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

最新更新