c++ - SQLite (C/C++) 的不区分大小写的 UTF-8 字符串排序规则

标签 c++ sqlite unicode utf-8 internationalization

我正在寻找一种以不区分大小写的方式在 C++ 中比较和排序 UTF-8 字符串的方法,以便在 custom collation function in SQLite 中使用它.

  1. 该方法理想情况下应该与语言环境无关。但是我不会屏住呼吸,据我所知,排序规则非常依赖于语言,因此任何适用于英语以外的语言的东西都可以,即使这意味着切换语言环境。
  2. 选项包括使用标准 C 或 C++ 库或小型(适用于嵌入式系统)和非 GPL(适用于专有系统)第三方库。

我目前拥有的:

    使用 C 语言环境的
  1. strcollstd::collat​​e/std::collat​​e_byname 区分大小写。 (是否有不区分大小写的版本?)
  2. 我尝试使用 POSIX strcasecmp,但它似乎是 not defined对于 "POSIX"

    以外的语言环境

    In the POSIX locale, strcasecmp() and strncasecmp() do upper to lower conversions, then a byte comparison. The results are unspecified in other locales.

    而且,事实上,strcasecmp 的结果在使用 GLIBC 的 Linux 上的语言环境之间不会改变。

    #include <clocale>
    #include <cstdio>
    #include <cassert>
    #include <cstring>
    
    const static char *s1 = "Äaa";
    const static char *s2 = "äaa";
    
    int main() {
        printf("strcasecmp('%s', '%s') == %d\n", s1, s2, strcasecmp(s1, s2));
        printf("strcoll('%s', '%s') == %d\n", s1, s2, strcoll(s1, s2));
        assert(setlocale(LC_ALL, "en_AU.UTF-8"));
        printf("strcasecmp('%s', '%s') == %d\n", s1, s2, strcasecmp(s1, s2));
        printf("strcoll('%s', '%s') == %d\n", s1, s2, strcoll(s1, s2));
        assert(setlocale(LC_ALL, "fi_FI.UTF-8"));
        printf("strcasecmp('%s', '%s') == %d\n", s1, s2, strcasecmp(s1, s2));
        printf("strcoll('%s', '%s') == %d\n", s1, s2, strcoll(s1, s2));
    }
    

    这是打印出来的:

    strcasecmp('Äaa', 'äaa') == -32
    strcoll('Äaa', 'äaa') == -32
    strcasecmp('Äaa', 'äaa') == -32
    strcoll('Äaa', 'äaa') == 7
    strcasecmp('Äaa', 'äaa') == -32
    strcoll('Äaa', 'äaa') == 7
    

P. S.

是的,我知道 ICU , 但由于它的 enormous size 我们不能在嵌入式平台上使用它.

最佳答案

你真正想要的在逻辑上是不可能的。没有独立于语言环境、不区分大小写的字符串排序方式。简单的反例是 "i"<> "I"?天真的答案是否定的,但在土耳其语中这些字符串是不相等的。 “i”大写为“İ”(U+130 拉丁大写字母 I,上面有点)

UTF-8 字符串给问题增加了额外的复杂性。如果您有适当的语言环境,它们是完全有效的多字节 char* 字符串。但是 C 和 C++ 标准都没有定义这样的语言环境;请咨询您的供应商(嵌入式供应商太多,抱歉,这里没有通用答案)。因此,您必须选择多字节编码为 UTF-8 的语言环境,才能使 mbscmp 函数正常工作。这当然会影响排序顺序,这取决于语言环境。如果您没有 const char* 为 UTF-8 的语言环境,则您根本无法使用此技巧。 (据我了解,Microsoft 的 CRT 受此影响。他们的多字节代码只能处理最多 2 个字节的字符;UTF-8 需要 3 个)

wchar_t 也不是标准的解决方案。它应该是如此之宽,以至于您不必处理多字节编码,但您的排序规则仍将取决于语言环境 (LC_COLLATE) 。但是,使用 wchar_t 意味着您现在选择的语言环境不使用 UTF-8 作为 const char*。

完成后,您基本上可以通过将字符串转换为小写字母并进行比较来编写自己的排序。这并不完美。你期望 L"ß"== L"ss"吗?它们甚至不一样长。然而,对于德国人来说,你必须认为他们是平等的。你能忍受吗?

关于c++ - SQLite (C/C++) 的不区分大小写的 UTF-8 字符串排序规则,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/181037/

相关文章:

c++ - 如何从示例 C 程序发送 HTTP post 请求

c++ - 如何使用 Qt oauth 创建登录页面?

android - 如何避免 "close() was never explicitly called on database in SQLiteDatabase"

debugging - 如何避免在 SQLite 表中插入错误的数据类型?

ios - Swift - 是否有像 SQLite 这样允许多个连接的本地数据库?

python - 如何处理电子邮件包中的 Python 3.x UnicodeDecodeError?

c++ - 这个递归函数是如何工作的?合并排序两个单链表

C++ 文件访问/输入和输出

csv - 在 Python CSV 模块中将分隔符更改为 CTRL+A

python - 为什么Python2和Python3对待相同的windows目录不同?