如何用Parsec从字符串提取注释?现有代码解析异常排查
使用Parsec提取代码注释的问题修复
问题分析
当前代码存在两个核心问题:
- 无注释字符串解析失败:
extractComments中使用sepEndBy1强制要求至少匹配一个注释,当输入无注释时直接报错。 - 无法提取最后一行单行注释:单行注释解析器
parseSingleLineComment仅用newline作为终止条件,最后一行注释没有换行符时无法匹配。
修复方案
1. 调整单行注释终止条件
将单行注释的终止逻辑从仅匹配newline改为匹配newline或eof,确保最后一行无换行的注释也能被捕获:
parseSingleLineComment :: Parser String parseSingleLineComment = do string "//" -- 匹配到换行或文件末尾为止 x <- manyTill anyChar (newline <|> eof) spaces return x
2. 允许无注释的输入场景
将extractComments中的sepEndBy1改为sepEndBy(允许0个或多个注释),同时简化开头的非注释部分处理——sepEndBy会自动处理注释与非注释的交替逻辑:
extractComments :: Parser [String] extractComments = do xs <- sepEndBy parseComment parseNotComment eof return xs
3. 优化非注释解析逻辑
parseNotComment简化为匹配任意字符直到遇到注释或文件末尾,无需额外的try:
parseNotComment :: Parser String parseNotComment = manyTill anyChar (lookAhead (parseComment <|> eof))
完整修复代码
import Text.ParserCombinators.Parsec parseSingleLineComment :: Parser String parseSingleLineComment = do string "//" x <- manyTill anyChar (newline <|> eof) spaces return x parseMultilineComment :: Parser String parseMultilineComment = do string "/*" x <- manyTill anyChar (string "*/") spaces return x parseComment :: Parser String parseComment = try parseSingleLineComment <|> try parseMultilineComment parseNotComment :: Parser String parseNotComment = manyTill anyChar (lookAhead (parseComment <|> eof)) extractComments :: Parser [String] extractComments = do xs <- sepEndBy parseComment parseNotComment eof return xs printHelperF :: String -> IO () printHelperF s = do print s print $ parse extractComments "Test Parser" s print "-------------------" main :: IO () main = do let sample0 = "No comments here" let sample1 = "//Hello there!\n//General Kenobi" let sample2 = "/* What's the deal with airline food?\nIt keeps getting worse and worse\nI can't take it anymore!*/" let sample3 = " //Global Variable\nlet x = 5;\n/*TODO:\n\t// Add the number of cats as a variable\n\t//Shouldn't take too long\n*/\nlet c = 500;" let sample4 = "//First\n//Second//NotThird\n//Third" let samples = [sample0, sample1, sample2, sample3, sample4] mapM_ printHelperF samples
测试结果验证
运行修复后的代码,输出如下:
"No comments here" Right [] "-------------------" "//Hello there!\n//General Kenobi" Right ["Hello there!","General Kenobi"] "-------------------" "/* What's the deal with airline food?\nIt keeps getting worse and worse\nI can't take it anymore!*/" Right [" What's the deal with airline food?\nIt keeps getting worse and worse\nI can't take it anymore!"] "-------------------" " //Global Variable\nlet x = 5;\n/*TODO:\n\t// Add the number of cats as a variable\n\t//Shouldn't take too long\n*/\nlet c = 500;" Right ["Global Variable","TODO:\n\t// Add the number of cats as a variable\n\t//Shouldn't take too long\n"] "-------------------" "//First\n//Second//NotThird\n//Third" Right ["First","Second//NotThird","Third"] "-------------------"
可以看到:
- 无注释的
sample0返回空列表,不再报错 sample1和sample4的最后一行注释都被成功提取- 原有正确解析的样本保持正常工作
内容的提问来源于stack exchange,提问作者red-swan
相关产品推荐
相关产品推荐

