-3

所以,我正在构建一种脚本语言,我的目标之一是方便的字符串操作。我在 C++ 中尝试了一些想法。

  • 字符串作为字节序列和返回包含代码点索引的向量的自由函数。
  • 一个包装类,它结合了一个字符串和一个包含索引的向量。

两种想法都有问题,问题是,我应该返回什么。它不能是一个字符,如果它是一个字符串,那将是浪费空间。

我最终围绕一个正好 4 个字节的 char 数组创建了一个包装类:一个在内存中正好有 4 个字节的字符串,不多也不少。

在创建这个类之后,我很想将它包装std::vector在另一个类中并从那里构建,从而制作一个字符串类型的代码点。我不知道这是否是一个好方法,它最终会更方便,但最终会浪费更多空间。

因此,在发布一些代码之前,这里有一个更有条理的想法列表。

  • 我的字符类型不是字节,也不是字素,而是代码点。我把它命名为一个符文,就像 Go 语言中的符文一样。
  • 一个字符串作为一系列分解的符文,从而对 O1 进行索引和切片。
  • 因为 rune 现在是一个类而不是原始类型,所以可以使用检测 unicode 空格的方法对其进行扩展:mysring[0].is_whitespace()
  • 我仍然不知道如何处理字素。

奇怪的事实!我构建 rune 类原型的方式的一个奇怪之处在于它总是以 UTF8 打印。因为我的 rune 不是 int32,而是一个 4 字节的字符串,所以最终会有一些有趣的属性。

我的代码:

class rune {
    char data[4] {};
public:
    rune(char c) {
        data[0] = c;
    }

    // This constructor needs a string, a position and an offset!
    rune(std::string const & s, size_t p, size_t n) {
        for (size_t i = 0; i < n; ++i) {
            data[i] = s[p + i];
        }
    }

    void swap(rune & other) {
        rune t = *this;
        *this = other;
        other = t;
    }

    // Output as UTF8!
    friend std::ostream & operator <<(std::ostream & output, rune input) {
        for (size_t i = 0; i < 4; ++i) {
            if (input.data[i] == '\0') {
                return output;
            }
            output << input.data[i];
        }
        return output;
    }
};

错误处理思路:

我不喜欢在 C++ 中使用异常。我的想法是,如果构造函数失败,则将 rune 初始化为 4 '\0',然后显式重载 bool 运算符以在运行的第一个字节恰好是 时返回 false '\0'。简单易用。

那么,想法?意见?不同的方法?

就算我的符文串很多,至少我还有符文类型。小而快复制。:)

4

1 回答 1

0

听起来您正在尝试重新发明轮子。

当然,您需要通过两种方式来考虑文本:

  • 作为代码点数组
  • 作为一个编码的字节数组。

在某些代码库中,这两种表示是相同的(并且所有编码基本上都是char32_tor的数组unsigned int)。在某些情况下(我倾向于说“大多数”,但不要引用我的话),编码的字节数组将使用 UTF-8,其中代码点在放入数据结构之前被转换为可变长度的字节.

当然,许多代码库只是完全忽略 unicode 并将其数据存储在 ASCII 中。我不建议这样做。

出于您的目的,虽然编写一个类来“包装”您的数据确实有意义(尽管我不会将其称为 a rune,但我可能只会将其称为 a codepoint),但您需要考虑您的语义。

  • 您可以(并且可能应该)将 all std::string's 视为 UTF-8 编码的字符串,并更喜欢将其作为处理 text 的默认接口。对于大多数外部接口来说它是安全的——它唯一会失败的时候是与 UTF-16 输入接口时,你可以为此编写极端情况——它会为你节省最多的内存,同时仍然遵守常见的字符串约定(它是字典上的可比性,这是最大的)。
  • 如果您需要以代码点形式处理数据,那么您需要编写一个名为 的结构(或类)codepoint,其中包含以下有用的函数和构造函数
    • 虽然我不得不编写以代码点形式处理文本的代码(特别是对于字体渲染器),但这可能不是您应该存储文本的方式。当您不断与 UTF-8 或 ASCII 编码字符串进行比较时,将文本存储为代码点会导致以后出现问题。

代码:

struct codepoint {
    char32_t val;
    codepoint(char32_t _val = 0) : val(_val) {}
    codepoint(std::string const& s);
    codepoint(std::string::const_iterator begin, std::string::const_iterator end);
    //I don't know the UTF-8→codepoint conversion off-hand. There are lots of places
    //online that show how to do this

    std::string to_utf8() const;
    //Again, look up an algorithm. They're not *too* complicated.
    void append_to_string_as_utf8(std::string & s) const;
    //This might be more performant if you're trying to reduce how many dynamic memory 
    //allocations you're making.

    //codepoint(std::wstring const& s);
    //std::wstring to_utf16() const;
    //void append_to_string_as_utf16(std::wstring & s) const;

    //Anything else you need, equality operator, comparison operator, etc.
};
于 2017-01-17T16:56:44.707 回答