6

我正在开发通过 Google API 将 Google 日历解析为DDay.iCal的应用程序

主要的属性,属性很容易处理... ev.Summary = evt.Title.Text;

问题是当我收到重复事件时,XML 包含如下字段:

<gd:recurrence>
    DTSTART;VALUE=DATE:20100916
    DTEND;VALUE=DATE:20100917
    RRULE:FREQ=YEARLY
</gd:recurrence>

或者

<gd:recurrence>
  DTSTART:20100915T220000Z
  DTEND:20100916T220000Z
  RRULE:FREQ=YEARLY;BYMONTH=9;WKST=SU"
</gd:recurrence>

使用以下代码:

    String[] lines = 
evt.Recurrence.Value.Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);

                    foreach (String line in lines)
                    {

                        if (line.StartsWith("R"))
                        {
                            RecurrencePattern rp = new RecurrencePattern(line);
                            ev.RecurrenceRules.Add(rp);
                        }
                        else 
                        {
                            ISerializationContext ctx = new SerializationContext();
                            ISerializerFactory factory = new DDay.iCal.Serialization.iCalendar.SerializerFactory();

                            ICalendarProperty property = new CalendarProperty();

                            IStringSerializer serializer = factory.Build(property.GetType(), ctx) as IStringSerializer;

                            property = (ICalendarProperty)serializer.Deserialize(new StringReader(line));

                            ev.Properties.Add(property);
                            Console.Out.WriteLine(property.Name + " - " + property.Value);
                        }

                    }

RRULE 被正确解析,但问题是其他属性(日期时间)值是空的......

4

2 回答 2

5

这是我正在做的事情的起点,脱离了 RFC-5545 规范的重复规则。它不符合规范,并且可能会因某些输入而中断,但它应该能让你继续前进。我认为这一切都应该可以使用 RegEx 来实现,而像递归体面解析器这样繁重的东西将是矫枉过正的。

RRULE:(?:FREQ=(DAILY|WEEKLY|SECONDLY|MINUTELY|HOURLY|DAILY|WEEKLY|MONTHLY|YEARLY);)?(?:COUNT=([0-9]+);)?(?:INTERVAL=([0-9]+);)?(?:BYDAY=([A-Z,]+);)?(?:UNTIL=([0-9]+);)?

我正在使用http://regexstorm.net/tester构建它。

我正在使用的测试输入是:

DTSTART;TZID=美国/芝加哥:20140711T133000\nDTEND;TZID=美国/芝加哥:20140711T163000\nRRULE:FREQ=每周;INTERVAL=8;BYDAY=FR;UNTIL=20141101

DTSTART;TZID=美国/芝加哥:20140711T133000\nDTEND;TZID=美国/芝加哥:20140711T163000\nRRULE:FREQ=WEEKLY;COUNT=5;INTERVAL=8;BYDAY=FR;UNTIL=20141101

DTSTART;TZID=美国/芝加哥:20140711T133000\nDTEND;TZID=美国/芝加哥:20140711T163000\nRRULE:FREQ=每周;BYDAY=FR;UNTIL=20141101

样本匹配结果如下所示:

Index    Position    Matched String                                                 $1      $2  $3  $4  $5
0        90          RRULE:FREQ=WEEKLY;INTERVAL=8;BYDAY=FR;UNTIL=20141101           WEEKLY      8   FR  20141101
1        236         RRULE:FREQ=WEEKLY;COUNT=5;INTERVAL=8;BYDAY=FR;UNTIL=20141101   WEEKLY  5   8   FR  20141101
2        390         RRULE:FREQ=WEEKLY;BYDAY=FR;UNTIL=20141101                      WEEKLY          FR  20141101

用法如下:

string freqPattern = @"RRULE:(?:FREQ=(DAILY|WEEKLY|SECONDLY|MINUTELY|HOURLY|DAILY|WEEKLY|MONTHLY|YEARLY);?)?(?:COUNT=([0-9]+);?)?(?:INTERVAL=([0-9]+);?)?(?:BYDAY=([A-Z,]+);?)?(?:UNTIL=([0-9]+);?)?";
MatchCollection mc = Regex.Matches(rule, freqPattern, System.Text.RegularExpressions.RegexOptions.IgnoreCase);
foreach (Match m in mc)
{
    string frequency = m.Groups[1].ToString();
    string count = m.Groups[2].ToString();
    string interval = m.Groups[3].ToString();
    string byday = m.Groups[4].ToString();
    string until = m.Groups[5].ToString();
    System.Console.WriteLine("recurrence => frequency: \"{0}\", count: \"{1}\", interval: \"{2}\", byday: \"{3}\", until: \"{4}\"", frequency, count, interval, byday, until);
}
于 2014-08-01T20:50:36.217 回答
-1

这是何时使用正则表达式的一个很好的例子。试试这个进行一般解析:

\s*(\w+):((\w+=\w+;)+(\w+=\w+)?|\w+)

或者,您可能决定使用更特定于模式的东西。

\s*(?:DTSTART:)(?'Start'\w+)
\s*(?:DTEND:)(?'End'\w+)
\s*(?:RRULE:)(?'Rule'(\w+=\w+;)+(\w+=\w+)?)
于 2011-07-09T20:56:27.443 回答