Megaparsec如何实现跳过空格与非字母数字字符的解析逻辑
Megaparsec 无关字符跳过逻辑修复
我是Megaparsec与Haskell的初学者,目前尝试编写符合以下文法规则的单词解析器:
单词始终属于以下三类之一:
- 由一个或多个ASCII数字组成的数字(例如
"0"或"1234");- 由一个或多个ASCII字母组成的简单单词(例如
"a"或"they");- 由单个撇号连接两个简单单词构成的缩写形式(例如
"it's"或"they're")。
已完成的基础实现
data Word = Number String | SimpleWord String | Contraction String deriving (Show) word :: Parser MyParser.Word word = M.choice [ Number <$> number , Contraction <$> contraction , SimpleWord <$> simpleWord ] number :: Parser String number = M.some C.numberChar simpleWord :: Parser String simpleWord = M.some C.letterChar contraction :: Parser String contraction = do left <- simpleWord void $ C.char '\'' right <- simpleWord return (left ++ "'" ++ right)
存在的问题
需要补充逻辑跳过空白、非字母数字的无关字符,要求输入为'abc'时,解析器丢弃两侧的撇号,仅识别其中的简单单词。最初编写的如下代码无法通过编译:
filler :: Parser Char filler = M.some (C.spaceChar A.<|> not C.alphaNumChar) spaceConsumer :: Parser () spaceConsumer = L.space filler A.empty A.empty lexeme :: Parser a -> Parser a lexeme = L.lexeme spaceConsumer
修复方案
错误根因
原代码存在三处语法与逻辑错误:
not C.alphaNumChar写法不合法:C.alphaNumChar是Parser Char类型的解析器,不是布尔值,无法直接传给not做逻辑取反。匹配不符合某类规则的字符需要用satisfy组合子,传入字符判断函数。L.space的第一个参数本身就要求匹配1个及以上的无关字符,不需要在外层额外套M.some。- 直接把所有撇号归为要跳过的字符会导致缩写解析失效,需要保留单词内部作为连接符的撇号,只跳过单词外侧的无关撇号。
修正后的代码
import qualified Data.Char as Char -- 匹配单个需要跳过的字符:空白字符,或既不是字母数字也不是单撇号的字符 skipChar :: Parser Char skipChar = C.spaceChar <|> M.satisfy (\c -> not (Char.isAlphaNum c || c == '\'')) spaceConsumer :: Parser () spaceConsumer = L.space (void $ M.some skipChar) A.empty A.empty lexeme :: Parser a -> Parser a lexeme = L.lexeme spaceConsumer -- 最终的单词解析器需要用lexeme包装,自动跳过单词前后的所有无关字符 word :: Parser MyParser.Word word = lexeme $ M.choice [ Number <$> number , Contraction <$> contraction , SimpleWord <$> simpleWord ]
逻辑说明
- 词法解析过程中,
lexeme会自动吃掉当前解析单元前后所有匹配skipChar的内容,因此'abc'前后的两个撇号会在解析abc前后被自动跳过,最终得到SimpleWord "abc"。 - 缩写结构里的撇号属于单词内部内容,在
contraction解析器运行时会被主动匹配,不会被外层的spaceConsumer跳过,可正常识别it's这类结构。 M.choice的匹配顺序保持Contraction在SimpleWord之前即可,避免缩写的左半段被提前匹配为简单单词导致解析失败。
内容的提问来源于stack exchange,提问作者Abhijit Sarkar
相关产品推荐
相关产品推荐

