如何使用 antlr4 解析 3 字节 utf8 字符串

How to use antlr4 to parse 3-byte utf8 string

提问人:user9634413 提问时间:11/23/2021 最后编辑:user9634413 更新时间:11/24/2021 访问量:390

问:

Blow 是我的语法文件。

grammar My;

tokens {
    DELIMITER
}

string:SINGLE_QUOTED_TEXT;

SINGLE_QUOTED_TEXT: (
        '\'' (.)*? '\''
    )+
;

我正在尝试使用它来访问所有字符串(它实际上是 mysql 的 g4 的一部分)。 然后我使用以下代码来测试它:

#include "MyLexer.h"
#include "MyParser.h"
#include <string>
using namespace My;

int main()
{
    std::string s = "'中'";

    antlr4::ANTLRInputStream input(s);
    MyLexer lexer(&input);

    antlr4::CommonTokenStream tokens(&lexer);
    MyParser parser(&tokens);

    parser.string();

    return 0;
}

结果是enter image description here

汉字 中 的 utf8 代码为 3 个字节:\xe4 \xb8 \xad

语法文件和代码文件都以 utf8 编码。 我能做些什么来让它工作正常。

C++ 正则表达 UTF-8 ANTLR ANTLR4

评论

0赞 sepp2k 11/24/2021
为什么屏幕截图中的输出包含双引号,而代码中的字符串仅包含单引号?你确定你运行的是你在这里发布的相同代码吗?
0赞 user9634413 11/24/2021
对不起,右截图已updated@sepp2k
0赞 kaby76 11/24/2021
语法/输入文件适用于 C# 和 Java 目标 v4.9.2。这可能是 C++ 运行时问题,但我用于生成和构建 C++ 目标解析器的工具不起作用,所以我无法检查。顺便说一句,我不知道你为什么要做一个“tokens”声明,人们通常称“SINGLE_QUOTED_TEXT”为单引号字符串,而不是通过 + 运算符闭包的多个字符串。

答:

0赞 user9634413 11/24/2021 #1

我已经弄清楚了问题所在。

参考 https://stackoverflow.com/a/26865200/9634413

Antlr C++运行时使用 std::u32string 来存储输入,\xe4 将被强制转换为 \xffffffe4,这超出了 unicode 范围 [0,0x10ffff]。

要解决此问题,只需重写 ANTLRInputStream 的构造函数,例如:

class MyStream : public antlr4::ANTLRInputStream {
public:
    MyStream(const std::string& input = "")
        : antlr4::ANTLRInputStream(input)
    {
        // Remove the UTF-8 BOM if present
        const char bom[4] = "\xef\xbb\xbf";
        if (input.compare(0, 3, bom, 3) == 0) {
            std::transform(input.begin() + 3, input.end(), _data.begin(),
                [](char c) -> unsigned char { return c; });
        }
        else {
            std::transform(input.begin(), input.end(), _data.begin(),
                [](char c) -> unsigned char { return c; });
        }
        p = 0;
    }
    MyStream(const char data_[], size_t numberOfActualCharsInArray)
        : antlr4::ANTLRInputStream(data_, numberOfActualCharsInArray)
    {
    }
    MyStream(std::istream& stream)
        : antlr4::ANTLRInputStream(stream)
    {
    }
};