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

如何基于Dart的Petit Parser实现带例外的分隔符终止消费

用Petit Parser实现支持单引号转义的分隔符感知词法分析器

你的基础实现仅处理了分隔符的直接否定匹配,未考虑单引号内的内容会屏蔽分隔符,也没处理单引号的转义逻辑。要实现需求,需拆分出单引号段的解析逻辑,确保单引号内的分隔符不触发终止,同时支持转义单引号。

完整实现代码

import 'package:petitparser/petitparser.dart';

Parser<String> fpLexer(List<String> delimiters) {
  // 优先匹配更长的分隔符,避免短分隔符提前截断长分隔符
  final delimiterChoice = delimiters
      .sorted((a, b) => b.length.compareTo(a.length))
      .map(string)
      .toChoiceParser();

  // 匹配转义单引号:\'
  final escapeSingleQuote = (char(r'\') & char("'")).map((pair) => pair.join());

  // 匹配单引号内的内容:允许转义单引号或非单引号字符
  final singleQuotedContent = (escapeSingleQuote | char("'").neg())
      .star()
      .map((chars) => chars.join());

  // 匹配完整的单引号段:'...'(包含内部转义)
  final singleQuoted = (char("'") & singleQuotedContent & char("'"))
      .map((parts) => '${parts[0]}${parts[1]}${parts[2]}');

  // 匹配普通字符:既不是分隔符也不是单引号的单个字符
  final normalChar = (delimiterChoice | char("'"))
      .neg()
      .map((char) => char.toString());

  // 匹配可消费的内容:由普通字符段或单引号段组成,重复直到遇到分隔符
  final content = (normalChar.plus() | singleQuoted)
      .star()
      .map((segments) => segments.join());

  return content;
}

代码逻辑说明

  1. 分隔符优先级处理:先对分隔符按长度降序排序,确保长分隔符(比如then)比短分隔符(比如单个字符)先被匹配,避免出现then被拆分为the+n的错误匹配。
  2. 转义单引号解析:单独匹配\',确保单引号内的转义单引号被视为普通内容,不会提前终止单引号段。
  3. 单引号段解析:匹配完整的单引号包裹内容,内部允许转义单引号或任意非单引号字符,整个单引号段会被当作普通内容消费,不会触发分隔符检查。
  4. 普通字符解析:匹配既不是分隔符也不是单引号的字符,确保这些字符被正常消费,直到遇到单引号或分隔符。
  5. 内容组合:重复匹配普通字符段或单引号段,直到遇到第一个有效分隔符(此时无法继续匹配,解析停止)。

测试示例验证

对于输入字符串:

'<a href=\"http://www.w3.org/1999/xhtml\">then</a>' some "Link"

指定分隔符为["\"", "then"]时,解析器会消费到"Link"前的",最终得到的内容是:

'<a href=\"http://www.w3.org/1999/xhtml\">then</a>' some 

原因是:

  • 单引号内的转义双引号\"和单词then都属于单引号段的一部分,不会被视为有效分隔符。
  • 第一个触发终止的有效分隔符是"Link"前的未被包裹的"。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 23:19:58