Я работаю в небольшой веб-хостинговой компании и решил написать скрипт для сортировки нашего довольно большого файла конфигурации зоны named/bind9. Я в некоторой степени доволен тем, как это получилось (по крайней мере, это работает), но меня немного беспокоит неизящность центральной функции синтаксического анализа. Для справки, типичное определение зоны выглядит так (на ведомом сервере. Мастер выглядит немного проще):
zone "somewebsite.com" {
masters { ip.ad.dr.ess; };
type slave;
allow-query { any; };
file "slave/db.somewebsite.com";
};
Файл заполнен примерно 190 из них. Что мне нужно от каждой зоны, так это имя сайта (для использования в качестве ключа сортировки) и вся строка, содержащая зону. Итак, вот мои парсеры (и крошечный тип данных для хранения имени зоны и ее полного текста):
type SortKey = String
type ZoneText = String
data Zone = Zone SortKey ZoneText deriving Show
allZonesParser :: Parser [Zone]
allZonesParser = do zones <- many zoneParser
return zones
zoneParser :: Parser Zone
zoneParser = do p1 <- string "zone"
p2 <- many space
p3 <- string "\""
zoneName <- many (alphaNum <|> oneOf ".-")
p4 <- string "\""
p5 <- many space
p6 <- manyTill anyChar (try (string ";" >> newline >> string "};"))
p7 <- many space
p8 <- many newline
return $ Zone zoneName (p1 ++ p2 ++ p3 ++ zoneName ++ p4 ++ p5 ++ p6 ++ ";\n};" ++ p7 ++ p8)
Я понимаю, что этот парсер не будет работать для всех вариантов использования, но для нашей конфигурации зоны он был достаточно продвинутым. Он захватывает весь раздел зоны, пока не найдет ;\n};
, а затем перестраивает текст зоны. И вот моя главная жалоба: я не могу понять, как сохранить всю строку, представляющую зону, без использования 9 монадических привязок, а затем объединения их вместе с оператором ++
. Есть ли элегантный способ потреблять весь этот ввод и сохранять/использовать все, что было проанализировано? Мне нужно использовать проанализированную строку позже, чтобы написать новый файл конфигурации отсортированной зоны, и кажется нелепым «реконструировать» строку так, как я сделал здесь. Я прочитал значительную часть документации Parsec, но не нашел правильного способа собрать это вместе.
Мой полный код находится здесь. Я бы посоветовал не использовать его, если вы не измените его, чтобы он соответствовал тому, как ваша конфигурация зоны разделена и разделена новой строкой.
compareZone
, но вместо этого вы можете использовать ту же реализацию для определенияOrd
вместоZone
, а затем вы можете просто использоватьsort
вместоsortBy compareZone
. Просто замените подписьcompareZone
наinstance Ord Zone where
, отступcompareZone's definition over, and rename it to
compare, then replace
sortBy compareZone` наsort
. Я бы посчитал это более идиоматичным Haskell - person bheklilr   schedule 31.07.2014lines
, чтобы получить каждую строку, затем удалите пробелы, добавьте" "
к каждой, затем используйтеunlines
, чтобы соединить их все вместе. Тогда вам не нужны все привязки. Вы также должны посмотреть на комбинаторbetween
, это поможет с вашей проблемой цитаты. - person bheklilr   schedule 31.07.2014