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

如何将自定义QA二叉树类型的字符串表示还原为原树结构

解决方法

你序列化的字符串是规则明确的嵌套括号结构,用递归下降解析即可完成反序列化,以下是两种可直接运行的实现方案:


方案1:手写递归解析(无额外依赖)

适合轻量场景,不需要引入第三方库:

-- 辅助函数:拆分平衡括号对,返回(括号内完整内容,括号外剩余字符串)
splitBalanced :: String -> (String, String)
splitBalanced s = go 0 0 s
  where
    go cnt pos [] = error "输入字符串括号不匹配"
    go cnt pos (x:xs)
      | x == '(' = go (cnt + 1) (pos + 1) xs
      | x == ')' = if cnt == 1 then (take pos s, drop (pos + 1) s) else go (cnt - 1) (pos + 1) xs
      | otherwise = go cnt (pos + 1) xs

-- 核心解析函数
parseQa :: String -> QA
parseQa s = let inner = init $ tail s -- 去掉当前节点首尾的括号
            in case break (== '(') inner of
                 -- 剩余内容无左括号,说明是Leaf节点
                 (content, "") -> Leaf content
                 -- 存在左括号,拆分问题文本、左右子树分别递归解析
                 (q, leftStr) ->
                   let (_, rightStr) = splitBalanced leftStr
                   in Question (parseQa leftStr) q (parseQa rightStr)

-- 读取文件并解析的完整入口
readQaFromFile :: FilePath -> IO QA
readQaFromFile path = do
  fileContent <- readFile path
  -- 自动去掉文件内容首尾的双引号
  let pureStr = read fileContent :: String
  return $ parseQa pureStr

方案2:Parsec库实现(更健壮)

如果项目允许引入依赖,用Parsec写的解析器错误提示更友好,扩展性更强:

import Text.Parsec
import Text.Parsec.String (Parser)

qaParser :: Parser QA
qaParser = do
  char '('
  content <- many1 $ noneOf "()"
  -- 没有子节点则为Leaf,有子节点则为Question
  option (Leaf content) $ do
    left <- qaParser
    right <- qaParser
    char ')'
    return $ Question left content right

parseQaParsec :: String -> Either ParseError QA
parseQaParsec = parse qaParser ""

注意事项

如果QA的问题/回答文本本身包含括号,需要先修改原有showQa函数对内容中的括号做转义处理,否则会导致解析错误,当前示例没有这类特殊字符可直接运行上述代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 19:54:03