Haskell Parsec и неупорядоченные свойства - PullRequest
6 голосов
/ 14 сентября 2010

Я пытаюсь использовать Parsec для разбора чего-то вроде этого:

property :: CharParser SomeObject
property = do
    name
    parameters
    value
    return SomeObjectInstance { fill in records here }

Я реализую спецификацию iCalendar и на каждом подобном есть имя: параметры: значение триплет, очень похоже на способ, которымXML имеет имя: атрибуты: триплет содержимого.На самом деле вы можете очень легко конвертировать iCalendar в формат XML (хотя я не вижу преимуществ).

Моя точка зрения заключается в том, что параметры не должны располагаться в любом порядке привсе и каждый параматер может иметь различный тип.Один параметр может быть строкой, а другой - числовым идентификатором другого элемента.Они могут не иметь общего сходства, в конце концов, я хочу правильно разместить их в нужных полях записи для любого «SomeObjectInstance», которое я хотел, чтобы парсер возвратил.Как мне поступить таким образом (или вы можете указать мне на пример, где кто-то должен был анализировать данные, подобные этим)?

Спасибо, я знаю, что мой вопрос, возможно, немного запутан, но это отражает мой уровень понимания того, что мне нужно делать.

Редактировать : Я пыталсяизбегайте выдачи ожидаемого результата (потому что он большой, а не потому, что он скрыт), но вот пример входного файла (из википедии):

НАЧАЛО: VCALENDAR
ВЕРСИЯ: 2.0
PRODID: - // hacksw / handcal // NONSGML v1.0 // EN
НАЧАТЬ: VEVENT
UID: uid1@example.com
DTSTAMP: 19970714T170000Z
ОРГАНИЗАТОР; CN = Джон Доу: MAILTO: john.doe@example.com
DTSTART: 19970714T170000Z
DTEND: 19970715T035959Z
РЕЗЮМЕ: Празднование Дня взятия Бастилии
КОНЕЦ: VEVENT
КОНЕЦ: VCALENDAR

Как вы видите, он содержит один VEvent внутри VCalendar, я создал структур данных, которые представляют их здесь .

Я пытаюсь написать парсер, который анализирует этот тип файла в моемструктуры данных, и я застрял на бит, где мне нужно обрабатывать приходящие свойствав любом порядке с любым типом;дата, время, int, строка, uid, т. д.Я надеюсь, что это имеет смысл без повторения всей спецификации iCalendar.

Ответы [ 2 ]

6 голосов
/ 14 сентября 2010

Parsec имеет модуль Parsec.Perm для точного анализа неупорядоченных, но линейных (т.е. на том же уровне в синтаксическом дереве) элементов, таких как теги атрибутов, в файлах XML.

К сожалению, модуль Perm в основном не документирован.Лучшим справочным материалом является статья «Парсинг-перестановочные фразы», ​​на которую ссылается страница документа «Хэддок», но даже это скорее описание техники, а не ее использования.

1 голос
/ 14 сентября 2010

Хорошо, поэтому между BEGIN:VEVENT и END:VEVENT у вас есть много пар ключ-значение. Поэтому напишите правило keyValuePair, которое возвращает (key, value). Теперь внутри правила для VEVENT вы делаете many KeyValuePair, чтобы получить список пар. Как только вы это сделаете, вы используете сгиб, чтобы заполнить запись VEVENT заданными значениями. В функции, которую вы даете сворачиванию, вы используете сопоставление с образцом, чтобы выяснить, в каком поле хранить значение. В качестве начального значения для аккумулятора вы используете запись VEvent, в которой дополнительные поля установлены на Nothing. Пример:

pairs <- many keyValuePairs
vevent = foldr f (VEvent {sequence = Nothing}) pairs
    where f ("SUMMARY", v) ve = ve {summary = v}
          f ("DSTART", v) ve = ve {dstart = read v}

... и так далее. Сделайте то же самое для других компонентов.

Редактировать: Вот пример работающего кода для сгиба:

data VEvent = VEvent {
        summary :: String,
        dstart :: String,
        sequenceSt :: Maybe String
        } deriving Show

vevent pairs = foldr f (VEvent {sequenceSt = Nothing}) pairs
    where f ("SUMMARY", v) ve = ve {summary = v}
          f ("DSTART", v) ve = ve {dstart = v}
          f ("SEQUENCEST", v) ve = ve {sequenceSt = Just v}

main = do print $ vevent [("SUMMARY", "lala"), ("DSTART", "lulu")]
          print $ vevent [("SUMMARY", "lala"), ("DSTART", "lulu"), ("SEQUENCEST", "lili")]

Выход:

VEvent {summary = "lala", dstart = "lulu", sequenceSt = Nothing}
VEvent {summary = "lala", dstart = "lulu", sequenceSt = Just "lili"}

Обратите внимание, что при компиляции выдается предупреждение. Чтобы избежать предупреждения, инициализируйте все необязательные поля явно undefined.

...