nom.rs中前置选项解析失败时如何停止解析后续其他选项?
问题根因
你的opt()解析器组合子存在语义设计缺陷:当内部包裹的解析器匹配失败时,它仅返回None作为解析结果,既没有消费当前待解析的输入片段,也没有向外层的tuple()序列组合子传递「后续可选解析器终止执行」的标记,导致后续的opt(parse_string)直接越位消费了本该属于parse_int匹配位置的字符串token。
对应你给出的异常场景,执行流程是:
- 输入
"dfs sdf"先经过第一个parse_string,消费掉"dfs",剩余待解析内容为"sdf" - 执行
opt(parse_int)时,尝试把开头的"sdf"解析为整数失败,按现有逻辑直接返回None,原封不动把"sdf"传给下一个解析器 - 执行
opt(parse_string)时,直接匹配到剩余的"sdf",返回Some("sdf"),最终得到不符合预期的结果("dfs", None, Some("sdf"))
修复方案
需要同时调整opt()和tuple()两个组合子的逻辑,增加可选解析失败的终止信号传递:
- 给
opt()增加信号返回逻辑:内部解析器匹配失败时,除了返回None和未消费的原输入,还要额外返回一个「终止后续可选解析」的标记 - 给
tuple()增加状态位:顺序执行解析器序列时,一旦收到opt()返回的终止信号,后续所有被opt()包裹的可选解析器直接返回None,不再消费输入内容
逻辑验证
修复后两个测试用例的表现都符合预期:
- 正常输入
" dsf 123 sdf":parse_string消费"dsf"后,opt(parse_int)成功匹配123,不触发终止信号,后续opt(parse_string)正常消费"sdf",返回("dsf", Some(123), Some("sdf")) - 异常输入
"dfs sdf":parse_string消费"dfs"后,opt(parse_int)匹配sdf失败,触发终止信号,后续opt(parse_string)直接返回None,最终返回("dfs", None, None)
伪代码参考
原有缺陷实现
def opt(parser): def wrapper(input_str): try: val, remaining = parser(input_str) return (Some(val), remaining) except ParseError: # 无状态标记,原输入直接透传给下一个解析器 return (None, input_str) return wrapper def tuple(parsers): def wrapper(input_str): results = [] remaining = input_str for p in parsers: val, remaining = p(remaining) results.append(val) return (tuple(results), remaining) return wrapper
修复后实现
# 定义可选解析终止的信号常量 STOP_OPTIONAL_PARSE = object() def opt(parser): def wrapper(input_str): try: val, remaining = parser(input_str) # 解析成功不触发终止信号 return (Some(val), remaining, None) except ParseError: # 解析失败返回None,同时传递终止信号 return (None, input_str, STOP_OPTIONAL_PARSE) return wrapper def tuple(parsers): def wrapper(input_str): results = [] remaining = input_str stop_optional = False for p in parsers: if stop_optional: # 收到终止信号后,所有可选解析器直接返回None results.append(None) continue val, remaining, signal = p(remaining) results.append(val) if signal == STOP_OPTIONAL_PARSE: stop_optional = True return (tuple(results), remaining) return wrapper
注意:终止逻辑仅对
opt()包裹的可选解析器生效,如果序列中存在未被opt包裹的必选解析器,即使收到终止信号,轮到它执行时仍要正常做解析校验,匹配失败直接抛出解析错误,不能跳过返回None,避免破坏必选参数的解析语义。
内容的提问来源于stack exchange,提问作者olegshmel
相关产品推荐
相关产品推荐

