如何将 C 字符数组中的变音符号转换为十六进制代码?

How to convert umlauts in a C char array to hex codes?

我的任务是将包含多个变音符号的字符数组转换为具有相应 ANSI 十六进制代码的字符数组,以便在终端中正确显示它。

ASCII ANSI

我的尝试是这样的:

#include <iostream>

using namespace std;

int main()
{
    char lied[] = "ÄäÖöÜüß\r\n";  // this syntax must remain the same


    cout << lied << endl;

    for (char* p = lied; *p != '[=10=]'; ++p)
    {
        char c;
        switch (*p)
        {
        case 'Ä': c = '\x8e'; break;
        case 'ä': c = '\x84'; break;
        case 'Ö': c = '\x99'; break;
        case 'ö': c = '\x94'; break;
        case 'Ü': c = '\x9a'; break;
        case 'ü': c = '\x81'; break;
        case 'ß': c = '\xe1'; break;
        default:
            c = *p;
            break;
        }

        *p = c;
    }
    
    cout << lied << endl;
}

显然我的解决方案不起作用,因为我发现无法以这种方式比较字符。似乎每个变音符号都由数组中的 2 个字符组成(它们都有负值)。如果我是对的,变音符号需要被解释为无符号字符,因为它们需要更多的内存来表示额外的符号。 这如何使用 C 风格的字符数组和指针来完成?

(除了 C++ input/output 流,我只被允许使用基本的 C)

我什至可以简单地覆盖变音符号,还是应该在循环时直接输出字符并在必要时替换它们? 我更喜欢先尝试第一种方法

我猜当你说“我想将变音符号转换成十六进制代码”时,你的意思是你想要字符串的 C 字符串表示,其中一些字符被编码为转义序列。

让我们这样做并处理以下字符:

  • 基本转义序列:制表符(\t)等特殊字符编码为反斜杠加一个字母。
  • hex escape characters: 所有其他不在 32 到 127 有效 ASCII 范围内的字符被编码为像 \xc0.
  • 这样的序列

这些转义使字符串变长,因此您无法就地编码字符串。创建另一个字符串,该字符串至少可以容纳原始字符串长度的四倍加上一个空终止符。

现在遍历原始字符串并随时转换:

#include <stdio.h>

int main(void)
{
    char lied[] = "\"Fix Schwyz!\" quäkt Jürgen blöd vom Paß.\r\n";
    char encoded[4 * sizeof(lied)];
    
    const char *p = lied;
    char *q = encoded;
    
    while (*p) {
        unsigned char c = *p++;
        
        switch (c) {
        case '"':   *q++ = '\'; *q++ = '"'; break;
        case '\r':  *q++ = '\'; *q++ = 'r'; break;
        case '\n':  *q++ = '\'; *q++ = 'n'; break;
        case '\t':  *q++ = '\'; *q++ = 't'; break;
        case '\a':  *q++ = '\'; *q++ = 'a'; break;
        case '\b':  *q++ = '\'; *q++ = 'b'; break;
        
        default:    if (c < 32 || c > 127) {
                        static const char *hex = "0123456789abcdef";
        
                        *q++ = '\';
                        *q++ = 'x';
                        *q++ = hex[c / 16];
                        *q++ = hex[c % 16];
                    } else {
                        *q++ = c;
                    }
        }
    }
    
    *q = '[=10=]';
    
    puts(encoded);
    
    return 0;
}

在使用 Latin1 (ISO-8859-1) 编码的语言环境中,这将打印:

\"Fix Schwyz!\" qu\xe4kt J\xfcrgen bl\xf6d vom Pa\xdf.\r\n

在 UTF-8 区域设置中,您应该看到每个非 ASCII 字符都有 hwo 转义十六进制代码。

注意事项:

  • 对于此解决方案,您不需要知道变音符号的确切代码,它们只是“非 ASCII”,就像其他重音字符或外来字符一样。
  • 这个解决方案不关心编码,只要给定一串字符即可。
  • 您的原始代码是 C++,因此您可以创建一个 std::string 并附加到它,而不是自己进行繁琐的分配计算。

你的问题不是很友好,因为它没有直接给出重要的东西。我可以从细节中猜到大部分:

您的 ASCII ANSI table 表明您需要 Window 代码页 850 编码以下字符 ÄäÖöÜüß

似乎每个变音符号由数组中的 2 个字符组成(均为负值):这意味着您的源文件当前是 UTF-8 编码的。

这是您需要的翻译table:

 char      utf-8   cp850
    Ä  "\xc3\x84"  "\x8e"
    ä  "\xc3\xa4"  "\x84"
    Ö  "\xc3\x96"  "\x99"
    ö  "\xc3\xb6"  "\x94"
    Ü  "\xc3\x9c"  "\x9a"
    ü  "\xc3\xbc"  "\x81"
    ß  "\xc3\x9f"  "\xe1"

我将您的代码更改为:

#include <iostream>

using namespace std;

int main()
{
    char lied[] = "ÄäÖöÜüß\r\n";  // this syntax must remain the same


    cout << lied << endl;

    int second = 0;

    char *q = lied;
    for (char* p = lied; *p != '[=11=]'; ++p)
    {
        if (*p == '\xc3') {
            second = 1;
        }
        else if (second) {
            char c;
            second = 0;
            switch (*p)
            {
            case '\x84': c = '\x8e'; break;
            case '\xa4': c = '\x84'; break;
            case '\x96': c = '\x99'; break;
            case '\xb6': c = '\x94'; break;
            case '\x9c': c = '\x9a'; break;
            case '\xbc': c = '\x81'; break;
            case '\x9f': c = '\xe1'; break;
            default:
                c = *p;
                break;
            }
            *q++ = c;
        }
        else {
            *q++ = *p;
        }
    }
    *q = 0;

    cout << lied << endl;
    return 0;
}

在我的 Windows 系统上的 CP850 控制台中,我得到了预期的结果:

├ä├ñ├û├Â├£├╝├ƒ

ÄäÖöÜüß