You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Megaparsec如何实现跳过空格与非字母数字字符的解析逻辑

Megaparsec 无关字符跳过逻辑修复

我是Megaparsec与Haskell的初学者,目前尝试编写符合以下文法规则的单词解析器:

单词始终属于以下三类之一:

  1. 由一个或多个ASCII数字组成的数字(例如"0"或"1234");
  2. 由一个或多个ASCII字母组成的简单单词(例如"a"或"they");
  3. 由单个撇号连接两个简单单词构成的缩写形式(例如"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

修复方案

错误根因

原代码存在三处语法与逻辑错误:

  1. not C.alphaNumChar写法不合法:C.alphaNumChar是Parser Char类型的解析器,不是布尔值,无法直接传给not做逻辑取反。匹配不符合某类规则的字符需要用satisfy组合子,传入字符判断函数。
  2. L.space的第一个参数本身就要求匹配1个及以上的无关字符,不需要在外层额外套M.some。
  3. 直接把所有撇号归为要跳过的字符会导致缩写解析失效,需要保留单词内部作为连接符的撇号,只跳过单词外侧的无关撇号。

修正后的代码

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 22:18:14