如何在Linux下使用C语言将非ASCII字符压缩为1个字节?

4

我有一份土耳其单词列表,需要比较它们的长度。但是由于一些土耳其字符不是ASCII,所以我无法正确比较它们的长度。非ASCII的土耳其字符占用2个字节。

例如:

#include <stdio.h>
#include <string.h>

int main()
{
    char s1[] = "ab";
    char s2[] = "çş";

    printf("%d\n", strlen(s1)); // it prints 2
    printf("%d\n", strlen(s2)); // it prints 4

    return 0;
}

我的朋友说可以通过以下代码在Windows上实现:

system("chcp 1254");

他说它会将土耳其字符填充到扩展ASCII表中。但是在Linux上不起作用。
有没有一种方法可以在Linux中实现这个功能?

2
这完全取决于您使用的编码方式。如果您使用UTF-8(这是Linux中的标准),确定字符串中编码的代码点数量并不是非常复杂;这里是基本信息(它是C++,但核心问题应该足够清楚)。 - Matteo Italia
3
取决于土耳其字符的编码方式,它们占用的字节数是不同的。理想情况下,您应该使用UTF-8编码,很可能已经在使用中了,但是它是可变长度的!另一方面,cp1254是一个8位(1字节)字符集,并且与UTF-8不兼容。("扩展" ASCII 并不存在) - Alastair McCormack
2
将其转换为UTF-16编码,规范化为NFC格式,然后统计双字节字符数。对于大多数语言表达来说,这已经足够了。 - Dragonthoughts
3
chcp 1254 命令用于在 Windows 控制台上设置代码页为土耳其语,表示高于一个字节的字符(约为 0xA0-FF)需要以土耳其语方式解释(如您所见到的字形)。在 Linux 上,这些字符是以 utf8 编码的,按照 @MatteoItalia 上面提供的方法很容易对它们进行计数。 - Déjà vu
1
好奇:为什么要在 strlen(s1) 中使用 "%d"?其他选择包括 "%u""%zu",... - chux - Reinstate Monica
显示剩余3条评论
2个回答

5

现在是2017年,很快就要到2018年了。因此,请到处使用UTF-8编码(对于最近的Linux发行版来说,UTF-8是最常见的编码方式,适用于大多数locale(7),并且肯定是您系统上的默认编码方式);当然,用UTF-8编码的Unicode字符可能有一到六个字节(因此,在某些UTF-8字符串中Unicode字符的数量不是通过strlen给出的)。考虑使用一些UTF-8库,如libunistring(或其他库,例如Glib)。

chcp 1254 是一些与 Windows 特定的东西,对于 UTF-8 系统来说不相关。所以忘记它吧。

如果你编写 GUI 应用程序,请使用像 GTKQt 这样的小部件工具包。它们都可以处理 Unicode 并能够接受(或转换为 UTF-8)。请注意,即使仅仅显示 Unicode(例如某些 UTF-8 或 UTF-16 字符串)也是很复杂的,因为一个字符串可能混合了阿拉伯语、日语、西里尔语和英语单词(需要在从左到右和从右到左的方向上显示),因此最好找到一个库(或其他工具,例如一个支持 UTF-8 的 终端模拟器)来完成这个任务。

如果你得到了某个文件,你需要知道它使用的编码(这只是一些你需要了解并遵循的惯例)。在某些情况下,file(1) 命令可能会帮助你猜测该编码,但你需要理解生成该文件所使用的编码惯例。如果它不是 UTF-8 编码,你可以转换它(前提是你知道源编码),也许可以使用 iconv(1) 命令来进行转换。

2

使用宽字符字符串来存储单词可能是一种解决方案。它不会将字符存储为一个字节,但可以解决您的主要问题,即使用您的语言设置一组功能。程序看起来像下面这样:

#include <stdio.h>
#include <string.h>
#include <wchar.h>

int main()
{
    wchar_t s1[] = L"ab";
    wchar_t s2[] = L"çş";

    printf("%d\n", wcslen(s1)); // it prints 2
    printf("%d\n", wcslen(s2)); // it prints 2

    return 0;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接