parsec:字符串选择解析器,包含有用的错误消息 [英] parsec: string choice parser with useful error messages

查看:151
本文介绍了parsec:字符串选择解析器,包含有用的错误消息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

让我们有以下解析器:

 解析器:: GenParser字符串
解析器=选择(fmap ,尾巴,故事])
<>预期的['head','tail','tales' code>

当我们解析格式错误的输入ta时,它会返回已定义的错误,但由于回溯,它还会讨论意外的t在第一个位置,而不是意外的在位置3。

是否有一种简单的(或内置的)方式来匹配产生好的错误消息的多个预期字符串之一?我说的是显示正确的位置,在这种情况下,像预计tail或tales,而不是硬编码的错误信息。

解决方案

制作一个正确执行此操作的函数并不困难。我们只需一次性删除一个字符,使用 Data.Map 查找共享后缀:



<$ p $($ lt; code> { - #LANGUAGE FlexibleContexts# - }
import Control.Applicative
import Data.Map hiding(empty)
import Text.Parsec hiding((< |>))
import Text.Parsec.Char

- 如果这是一个选项,接受空字符串
possibleEmpty :: Stream sm Char => [字符串] - > ParsecT s u m字符串
可能是空的ss | elem` ss =纯
|否则=空

chooseFrom :: Stream s m Char => [字符串] - > parsecT sum String
chooseFrom ss
= foldWithKey(\ h ts parser - > liftA2(:)(char h)(chooseFrom ts)< |> parser)
empty
(fromListWith(++)[(h,[t])| h:t <-ss])
< |>可能是空的ss

我们可以在ghci中验证它是否成功匹配tail / code>和tales,并要求 i ta

  *主>解析(chooseFrom [head,tail,tales])tail
右尾
* Main>解析(chooseFrom [head,tail,tales])tales
正确的故事
* Main>解析(chooseFrom [head,tail,tales])tafoo
Left(line 1,column 3):
unexpectedf
expecti 或l


Let's have following parser:

parser :: GenParser Char st String
parser = choice (fmap (try . string) ["head", "tail", "tales"]
                    <?> "expected one of ['head', 'tail', 'tales']")

When we parse the malformed input "ta" it will return the defined error but because of backtracking it will also talk about unexpected "t" at first position instead of unexpected " " at position 3.

Is there an easy (or built-in) way of matching one of multiple expected strings that produces good error messages? I am talking about showing the correct position and in this case something like expected "tail" or "tales" instead of our hard-coded error message.

解决方案

It's not hard to cook up a function which does this correctly. We'll just rip one character off at a time, using Data.Map to find the shared suffixes:

{-# LANGUAGE FlexibleContexts #-}
import Control.Applicative
import Data.Map hiding (empty)
import Text.Parsec hiding ((<|>))
import Text.Parsec.Char

-- accept the empty string if that's a choice
possiblyEmpty :: Stream s m Char => [String] -> ParsecT s u m String
possiblyEmpty ss | "" `elem` ss = pure ""
                 | otherwise    = empty

chooseFrom :: Stream s m Char => [String] -> ParsecT s u m String
chooseFrom ss
     =  foldWithKey (\h ts parser -> liftA2 (:) (char h) (chooseFrom ts) <|> parser)
                    empty
                    (fromListWith (++) [(h, [t]) | h:t <- ss])
    <|> possiblyEmpty ss

We can verify in ghci that it succesfully matches "tail" and "tales", and that it asks for i or l after a failed parse starting with ta:

*Main> parse (chooseFrom ["head", "tail", "tales"]) "" "tail"
Right "tail"
*Main> parse (chooseFrom ["head", "tail", "tales"]) "" "tales"
Right "tales"
*Main> parse (chooseFrom ["head", "tail", "tales"]) "" "tafoo"
Left (line 1, column 3):
unexpected "f"
expecting "i" or "l"

这篇关于parsec:字符串选择解析器,包含有用的错误消息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆