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

如何在RE/flex词法分析器中匹配对称引号包裹的任意内容?

解决RE/flex匹配对称单引号包裹双引号字符串并支持无效UTF8的问题

需要用RE/flex实现匹配如下语法的字符串:

  • 合法示例:"foo"、''"bar"''(对称数量的单引号包裹双引号,内部是任意内容)
  • 非法示例:''"baz"'(单引号数量不对称)

RE/flex不支持前瞻、后顾和反向引用,原实现的问题是只能匹配有效UTF8内容,无法处理无效UTF8序列,尝试过的三种方案均有缺陷:

  1. 使用skip()会消耗内容无法保留
  2. 用.*?"匹配合法字符串有效,但未终止的字符串会导致lexer卡住
  3. 逐个字符用.匹配支持无效UTF8但速度过慢

核心思路

利用RE/flex的字节级字符类匹配特性,用[^\x22]*替代原有的[^"]*:

  • [^\x22]按字节匹配任意非双引号(0x22)的字节,包括无效UTF8序列
  • 批量匹配非双引号字节,保证效率,同时支持无效UTF8
  • 保留原有的对称分隔符长度校验逻辑,确保单引号数量对称

修改后的Lex代码

%x STRING

%%

'*\x22 {
    textLen = 0uz;
    quoteLen = size(); // 记录开头分隔符总长度:n个单引号 + 1个双引号
    start(STRING);
}

<STRING> {

\x22'* {
    // 校验结尾分隔符长度是否和开头一致(保证单引号数量对称)
    if (size() != quoteLen) goto MORE_TEXT;
    // 截断匹配结果,仅保留字符串内容部分
    matcher().less(textLen + quoteLen);
    start(INITIAL);
    res = std::string{matcher().begin(), textLen};
    return TokenKind::STR;
}

[^\x22]* {
    MORE_TEXT:
    textLen += size(); // 累积字符串内容长度
    matcher().more(); // 继续匹配后续内容
}

<<EOF>> {
    std::cerr << "Lexical error: Unterminated 'STRING'\n";
    return TokenKind::ERR;
}

}

%%

方案优势

  1. 支持无效UTF8:[^\x22]*按字节匹配,捕获所有非双引号字节,包括无效UTF8序列
  2. 高效匹配:批量匹配连续非双引号字节,速度和原[^"]*相当,远快于逐个字符匹配
  3. 避免卡住:未终止的字符串会触发<<EOF>>规则,返回明确的 lexical error,不会无限扫描
  4. 保留内容:通过textLen累积内容长度,最终提取完整字符串内容,无需skip()

关键细节说明

  • '*\x22:匹配开头的n个单引号+1个双引号,用size()记录分隔符总长度(n+1)
  • \x22'*:匹配结尾的1个双引号+m个单引号,通过size() == quoteLen确保m == n(单引号数量对称)
  • [^\x22]*:批量匹配任意非双引号字节,包括无效UTF8,解决原代码仅支持有效UTF8的问题
  • matcher().more():将当前匹配的内容累积到后续匹配中,实现跨token的内容拼接

内容的提问来源于stack exchange,提问作者Sourav Kannantha B

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 22:45:59