4

正規表現を使用して 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

しかし、上記の入力を考えると、+? キャプチャ グループ:

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

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

最初の一致では、abc:123 と def:456 の 2 つのフィールドが一致すると予想していました...

これは初心者の間違いだと確信しています(正規表現に関しては、私は永遠に初心者であるように思われるため...)-しかし、正しい方向に私を向けることができますか?

ありがとう!

4

5 に答える 5

2

VEVENT正規表現を a に一致するものと名前/値のペアに一致するものに分割する必要があります。次に、ネストされたを使用scanして、すべての出現を見つけることができます。

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

于 2012-10-27T10:33:30.960 に答える
2

icalendarジェムを使用します。詳細については、iCalendar の解析セクションを参照してください。

于 2012-10-26T22:37:29.487 に答える
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
于 2012-10-26T23:52:39.433 に答える
0

MatchData問題は、正規表現が結果を返すルビーオブジェクトに、同じ名前の複数の値に対する規定がないことだと思います。したがって、2 番目の一致は最初の一致を上書きします。

于 2012-10-26T23:01:06.433 に答える
0

slice_beforeRuby には、このニーズによく適合する、めったに使用されないというメソッドがあります。

'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"]]

mapそして、そこから結果の各文字列をandを使用して分割するのは簡単split(':')です。

すべてを実行しようとする正規表現のサイレン コールに惑わされないでください。それらは特定の場所では非常に強力で便利ですが、多くの場合、よりシンプルで維持しやすいソリューションがあります。

于 2012-10-27T01:08:07.153 に答える