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

Java PetitParser提取标记内容报预期输入结束错误如何解决

问题根因分析
  • 当前报错是因为所有expr匹配完成后,输入末尾的剩余else内容没有被任何规则消耗,导致start规则末尾的end()校验失败,触发「期望输入结束」的异常
  • 原有else规则强制要求必须匹配换行符nl,如果输入最后一行没有换行,哪怕想匹配末尾内容也会失败
  • 你把跨expr的else匹配放到了expr规则内部,最后一个expr结束后没有下一个expr_start作为starLazy的终止条件,导致末尾else无法匹配
可行修改方案

按照以下逻辑调整规则即可解决问题:

  1. 把前后else的匹配逻辑从expr规则中剥离,放到外层start规则统一处理,避免内部逻辑冲突
  2. 重构else规则,支持两种场景:带换行的普通行、无换行的末尾行
  3. 调整start规则结构为「开头可选else + (expr + 中间可选else).star() + 末尾可选else + end()」,确保所有输入内容都被完全消耗
  4. 简化expr规则,只负责匹配start标记到end标记的区间,专心返回Body对象
修改后的完整代码
public class ExpressionDefinition extends GrammarDefinition {
        {
            // 整体规则:消耗所有内容后结束
            def("start", 
                ref("else").optional()
                .seq(ref("expr").star(
                    // 每个expr后面跟可选的中间else
                    ref("else").optional()
                ))
                .seq(ref("else").optional())
                .end()
                // 遍历结果只保留Body对象
                .map(in -> {
                    List<Object> all = (List<Object>) in;
                    return all.stream()
                        .filter(o -> o instanceof Body)
                        .toList();
                })
            );
            def("nl",  of("\r\n").or(of("\n")).or(of("\r")));
            // 简化expr规则:只匹配起止标记和中间内容
            def("expr", 
                    ref("expr_start")
                    .seq(ref("expr_body"))
                    .seq(ref("expr_end"))
                    .map(in -> ((List<Object>)in).get(1)) // 直接返回body
            );
            def("expr_start", of("--Start Query").seq(any().starLazy(ref("nl")), ref("nl")));
            def("expr_body", any().starLazy(ref("expr_end")).flatten().map((String in) -> new Body(in)));
            // 修正end规则:兼容后面无换行的场景
            def("expr_end", of("--End").seq(any().starLazy(ref("nl").or(end()))));
            // 重构else规则:支持末尾无换行场景
            def("else", 
                // 要么是带换行的普通行,要么是到输入结束的内容
                any().starLazy(ref("nl").or(ref("expr_start")).or(end()))
                .seq(ref("nl").optional())
            );
        }
}
验证效果

修改后运行解析代码,返回结果就是所有提取到的Body对象列表,对应示例输入中的important 1和important 2,同时兼容输入末尾有无换行的场景,不会出现贪婪吞掉后续expr、无限循环的问题,也不会有残留内容导致结束校验失败。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.12 03:03:03