Haskell Parsec:使用和保存输入的优雅方式

Haskell Parsec:使用和保存输入的优雅方式,haskell,parsec,named,Haskell,Parsec,Named,我在一家小型网络托管公司工作,决定编写一个脚本来对我们相当大的命名/bind9区域配置文件进行排序。我对结果有点满意(至少它是有效的),但是中心解析函数的不雅让我有点困扰。作为参考,典型的区域定义如下所示(在从属服务器上。主服务器看起来更简单): 该文件中有大约190个这样的文件。我需要每个区域的站点名称(用作排序键)和包含该区域的整个字符串。下面是我的解析器(和一个保存区域名称及其全文的小数据类型): type SortKey=String 类型ZoneText=String 数据区域=区域S

我在一家小型网络托管公司工作,决定编写一个脚本来对我们相当大的命名/bind9区域配置文件进行排序。我对结果有点满意(至少它是有效的),但是中心解析函数的不雅让我有点困扰。作为参考,典型的区域定义如下所示(在从属服务器上。主服务器看起来更简单):

该文件中有大约190个这样的文件。我需要每个区域的站点名称(用作排序键)和包含该区域的整个字符串。下面是我的解析器(和一个保存区域名称及其全文的小数据类型):

type SortKey=String
类型ZoneText=String
数据区域=区域SortKey ZoneText派生显示
AllZoneSpaser::解析器[区域]

allZonesParser=do zones使用Parsec,您当然可以做得更短,下面是我的想法

zoneParse = do
    string "zone"
    space1 <- many space
    zoneName <- between (char '"') (char '"') (many $ noneOf "\"")
    body <- manyTill anyChar (try $ string ";\n};")
    return $ Zone zoneName $ concat ["zone", space1, "\"", zoneName, "\"", body, ";\n};"]
zoneParse=do
字符串“区域”

space1为什么不将区域规范解析为自定义数据类型,然后为该类型配备专用的漂亮打印机?当打印出来时,您真的需要保留缩进和空白吗?完整代码的另一个注释是,您定义了
compareZone
,但是您可以使用相同的实现来定义
Ord
,而不是
区域
,然后,您只需使用
排序
,而不必使用
sortBy compareZone
。只需将
compareZone
的签名替换为
instance Ord Zone where
,缩进
compareZone的定义,并将其重命名为
compare
,然后将
sortBy compareZone`替换为
sort
。我会认为这更习惯Haskell@bheklilr谢谢你的回复!我认为这对于一个更大的通用脚本来说是很有意义的,但我正试图找出在这个用例中更优雅的解决方案是什么。如果我有一个数据类型来完整地表示区域定义,那么我最终会得到一个可以说更正确但似乎设计过度的脚本。我是否误解了你的评论?至于你的第二点意见:我完全同意,谢谢你的建议。这只是我的盲目。这将是更多的工作,对你来说,这可能被认为是设计过度。如果您想避免这种情况,可以使用Haskell提供的一些更简单的技术。解析第一行,找到最后一行,并存储中间的所有文本。使用
获取每一行,然后去掉空白,在每一行前面加上
,然后使用
取消行
将它们重新连接在一起。那你就不需要所有的束缚了。你也应该看看
之间的
组合器,它会帮助你解决报价问题。我希望我能给你一个答案。是的,我对Haskell的思维方式还是有点陌生,这是我第一次勇敢地在系统管理脚本中使用它。所以我要说的是,我问的问题并不是Parsec设计的目的。我可以接受。为了我自己的教育,我将尝试使用您的想法重写解析函数。
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)
zoneParse = do
    string "zone"
    space1 <- many space
    zoneName <- between (char '"') (char '"') (many $ noneOf "\"")
    body <- manyTill anyChar (try $ string ";\n};")
    return $ Zone zoneName $ concat ["zone", space1, "\"", zoneName, "\"", body, ";\n};"]