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

如何用Megaparsec将~{...}格式注释解析为Comment记录?

使用Megaparsec解析~{content}格式注释的解决方案

核心思路

要实现需求,我们需要同时处理两种内容:匹配并提取目标格式的注释,以及忽略所有非目标格式的内容(包括单独的~、{或})。通过组合两种解析器,重复扫描整个输入,最终只保留解析出的Comment记录即可。

完整代码实现

import Text.Megaparsec
import Text.Megaparsec.Char
import qualified Text.Megaparsec.Char.Lexer as L
import Data.Void (Void)

type Parser = Parsec Void String

data Comment = Comment
  { commentId :: Integer  -- 避免与Prelude的id重名
  , content :: String
  } deriving (Eq, Show)

-- 解析单个Comment记录
commentParser :: Parser Comment
commentParser = do
  string "~{"
  commentId <- L.decimal
  char '-'
  content <- takeWhileP Nothing (/= '}')
  char '}'
  return $ Comment commentId content

-- 解析并忽略非目标格式的内容(含单独的~、{、})
skipNonComment :: Parser ()
skipNonComment = do
  -- 确保不会误匹配目标格式的开头~{
  notFollowedBy (string "~{")
  -- 匹配任意单个字符并丢弃
  void anySingle

-- 最终解析器:收集所有有效Comment
parseComments :: Parser [Comment]
parseComments = many $ (Just <$> commentParser) <|> (skipNonComment >> return Nothing)
  >>= maybe (return []) (\c -> return [c])

-- 测试输入
testInput :: String
testInput = "hello world ~{1-sometext} bla bla ~{2-another comment}"

关键部分解释

  • commentParser:严格匹配~{id-content}格式,先识别开头的~{,解析整数id,读取分隔符-,再捕获到}为止的文本作为注释内容,最后匹配闭合的}并构造Comment。
  • skipNonComment:通过notFollowedBy (string "~{")规避对目标格式开头的误匹配,然后匹配任意单个字符并丢弃,以此忽略所有无关文本和单独的符号。
  • parseComments:用many重复执行两种操作——要么解析出Comment包装为Just,要么跳过非目标内容返回Nothing,最后过滤掉Nothing,只保留有效Comment列表。

测试结果

运行parseTest parseComments testInput会输出:

[Comment {commentId = 1, content = "sometext"}, Comment {commentId = 2, content = "another comment"}]

内容的提问来源于stack exchange,提问作者Niek

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 05:30:44