Parsing Parsec:处理重叠的解析器
我对Haskell中的解析非常陌生,但它基本上是有意义的 我正在构建一个模板程序,主要是为了更好地学习解析;模板可以通过Parsing Parsec:处理重叠的解析器,parsing,haskell,parsec,Parsing,Haskell,Parsec,我对Haskell中的解析非常陌生,但它基本上是有意义的 我正在构建一个模板程序,主要是为了更好地学习解析;模板可以通过{{value}}符号插入值 这是我当前的解析器 data Template a = Template [Either String a] data Directive = Directive String templateFromFile :: FilePath -> IO (Either ParseError (Template Directive)) templa
{{value}}
符号插入值
这是我当前的解析器
data Template a = Template [Either String a]
data Directive = Directive String
templateFromFile :: FilePath -> IO (Either ParseError (Template Directive))
templateFromFile = parseFromFile templateParser
templateParser :: Parser (Template Directive)
templateParser = do
tmp <- template
eof
return tmp
template :: Parser (Template Directive)
template = Template <$> many (dir <|> txt)
where
dir = Right <$> directive
txt = Left <$> many1 (anyChar <* notFollowedBy directive)
directive :: Parser Directive
directive = do
_ <- string "{{"
txt <- manyTill anyChar (string "}}")
return $ Directive txt
当我使用templateFromFile./template.txt“
运行此命令时,我得到错误:
Left "./template.txt" (line 5, column 17):
unexpected Directive " expression "
为什么会发生这种情况?我如何修复它
我的基本理解是many1(anyChar
当在中间解析文本时,它将在最后的<代码> t>代码>停止,在指令未被消耗之前留下新行(因为它是一个字符,后面跟着一个指令)。,因此,在下一次迭代中,您尝试解析一个指令,但失败。然后在该换行符上重试
txt
,解析器希望它后面没有一个指令,但它找到了一个,因此出现了错误
当在中间解析文本时,它将在最后的<代码> t>代码>停止,在指令未被消耗之前留下新行(因为它是一个字符,后面跟着一个指令)。,因此下一次迭代,您尝试解析一个指令,但失败了。然后在该换行符上重试
txt
,解析器希望它后面没有一个指令,但它找到了一个,因此出现了错误。您有几个问题。首先,在Parsec中,如果解析器使用任何输入,然后失败,这就是一个错误。因此,当解析器:
anyChar <* notFollowedBy directive
let p1 = many1 (anyChar <* notFollowedBy directive)
如果遇到指令,将永远不会成功。例如:
parse p1 "" "okay" -- works
parse p1 "" "oops {{}}" -- will fail after consuming "oops "
您可以通过插入try
子句来解决此问题:
let p2 = many1 (try (anyChar <* notFollowedBy directive))
parse p2 "" "okay {{}}"
它首先检查,在当前位置,在抓取字符之前,我们没有查看指令。不需要try
子句,因为如果失败,它将在不使用输入的情况下失败。(notfollowerdby
从不使用输入,如文档所示。)
因此,以您最初的示例为例:
txt = Left <$> many1 (notFollowedBy directive *> anyChar)
txt=Left many1(不遵循指令*>anyChar)
应该可以正常工作。您有几个问题。首先,在Parsec中,如果解析器使用任何输入,然后失败,那就是一个错误。因此,当解析器:
anyChar <* notFollowedBy directive
let p1 = many1 (anyChar <* notFollowedBy directive)
如果遇到指令,将永远不会成功。例如:
parse p1 "" "okay" -- works
parse p1 "" "oops {{}}" -- will fail after consuming "oops "
您可以通过插入try
子句来解决此问题:
let p2 = many1 (try (anyChar <* notFollowedBy directive))
parse p2 "" "okay {{}}"
它首先检查,在当前位置,在抓取字符之前,我们没有查看指令。不需要try
子句,因为如果失败,它将在不使用输入的情况下失败。(notfollowerdby
从不使用输入,如文档所示。)
因此,以您最初的示例为例:
txt = Left <$> many1 (notFollowedBy directive *> anyChar)
txt=Left many1(不遵循指令*>anyChar)
应该没问题。
是一个用于执行搜索并替换为解析器的库
搜索和替换功能不可用
,
它可以找到您的{{value}}
模式,然后替换为其他文本
streamEdit
是从通用版本构建的
调用的模板
函数的
import Replace.Megaparsec
导入文本.Megaparsec
导入Text.Megaparsec.Char
导入数据.Char
输入=未线
[“{{value}}”
, ""
,“这是普通文本”
, ""
,“{{expression}}”
]
指令::Parsec无效字符串
指令=do
_
是一个用于执行搜索并替换为解析器的库
搜索和替换功能不可用
,
它可以找到您的{{value}}
模式,然后替换为其他文本
streamEdit
是从通用版本构建的
调用的模板
函数的
import Replace.Megaparsec
导入文本.Megaparsec
导入Text.Megaparsec.Char
导入数据.Char
输入=未线
[“{{value}}”
, ""
,“这是普通文本”
, ""
,“{{expression}}”
]
指令::Parsec无效字符串
指令=do
_有意义;我如何才能最好地修复它以实现我的期望?txt=many1(notFollowedBy directive*>anyChar)
是最简单的修复,尽管它每个指令运行两次directive
。有意义;我如何才能最好地修复它以实现我的期望?txt=many1(notFollowedBy directive*>anyChar)
是最简单的修复方法,尽管每个指令运行两次指令。