2

编辑: 我只能使用 stdio.h 和 stdlib.h

我想遍历一个充满字符的字符数组。

然而,像 ä,ö 这样的字符占用了两倍的空间并使用了两个元素。这就是我的问题所在,我不知道如何访问那些特殊字符。

在我的示例中,字符“ä”将使用 hmm[0] 和 hmm[1]。

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

int main()
{
  char* hmm = "äö";

  printf("%c\n", hmm[0]); //i want to print "ä"

  printf("%i\n", strlen(hmm));

  return 0;
}

谢谢,我试图在 Eclipse 中运行我的附加代码,它在那里工作。我假设是因为它使用 64 位并且“ä”有足够的空间来容纳。strlen 确认每个“ä”仅计为一个元素。所以我想我可以以某种方式告诉它为每个字符分配更多空间(所以“ä”可以适合)?

#include <stdio.h>
#include <stdlib.h>

int main()
{
 char* hmm = "äüö";

  printf("%c\n", hmm[0]);
  printf("%c\n", hmm[1]);
  printf("%c\n", hmm[2]);

  return 0;
}
4

4 回答 4

4

一个字符总是使用一个字节。

在您的情况下,您认为“ä”是一个字符:错误。使用十六进制查看器打开您的 .c 源代码,您将看到 ä 使用 2 个字符,因为该文件以 UTF8 编码

现在的问题是你想使用宽字符吗?

#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
#include <locale.h>

int main()
{
    const wchar_t hmm[] = L"äö";

    setlocale(LC_ALL, "");
    wprintf(L"%ls\n", hmm);
    wprintf(L"%lc\n", hmm[0]);
    wprintf(L"%i\n", wcslen(hmm));

    return 0;
}
于 2012-12-29T16:43:00.370 回答
2

您的数据采用多字节编码。因此,您需要使用多字节字符处理技术来划分字符串。例如:

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

int main(void)
{
    char* hmm = "äö";
    int off = 0;
    int len;
    int max = strlen(hmm);

    setlocale(LC_ALL, "");

    printf("<<%s>>\n", hmm);
    printf("%zi\n", strlen(hmm));

    while (hmm[off] != '\0' && (len = mblen(&hmm[off], max - off)) > 0)
    {
        printf("<<%.*s>>\n", len, &hmm[off]);
        off += len;
    }

    return 0;
}

在我的 Mac 上,它产生了:

<<äö>>
4
<<ä>>
<<ö>>

呼吁setlocale()至关重要;没有它,程序在“C”语言环境而不是我的en_US.UTF-8语言环境中运行,并且mblen()处理不当:

<<äö>>
4
<<?>>
<<?>>
<<?>>
<<?>>

出现问号是因为就 UTF-8 终端而言,正在打印的字节是无效的单个字节。

您还可以使用宽字符和宽字符打印,如benjarobin答案所示。

于 2012-12-29T17:08:04.970 回答
1

抱歉拖到这里。虽然我认为强调一些问题很重要。据我了解,OS-X 能够将默认 OS 代码页设置为 UTF-8,因此答案主要是关于在后台使用 UTF-16 的 Windows,其默认 ACP 代码页取决于指定的操作系统区域。

首先你可以打开Character Map,找到
äö

两者都位于代码页 1252(西部)中,因此这不是MBCS 问题。可能是 MBCS 问题的唯一方法是使用 MBCS(Shift-JIS、Big5、Korean、GBK)编码保存文件。

使用
setlocale( LC_ALL, "" )的答案

没有深入了解 äö 在命令提示符窗口中错误呈现的原因。

命令提示符确实使用自己的代码页,即 OEM 代码页。是对以下 (OEM) 代码页及其字符映射的参考。

进入命令提示符并键入以下命令 (Chcp)将显示命令提示符正在使用的当前 OEM 代码页。

通过使用 setlocal(LC_ALL,"") 遵循 Microsoft 文档,它详细说明了以下行为。

设置语言环境(LC_ALL,“”);
将语言环境设置为默认值,即从操作系统获取的用户默认 ANSI 代码页。

您可以手动执行此操作,方法是使用 chcp 并传递您所需的代码页,然后运行您的应用程序,它应该可以完美地输出文本。

如果这是一个多字节字符集问题,那么将会有其他问题的完整列表:

在 MBCS 下,字符被编码为一个或两个字节。在双字节字符中,第一个或“前导字节”表示它和后面的字节都将被解释为一个字符。第一个字节来自保留用作前导字节的一系列代码。哪些字节范围可以是前导字节取决于使用的代码页。例如,日语代码页 932 使用 0x81 到 0x9F 范围作为前导字节,但韩语代码页 949 使用不同的范围。

看看情况,长度是 4 而不是 2。我会说文件格式已保存为 UTF-8(它实际上可以保存为 UTF-16,尽管您会很快遇到问题稍后与编译器一起使用)。您使用的字符不在 0 到 127 的 ASCII 范围内,UTF-8 将 Unicode 代码点编码为两个字节。您的编译器正在打开文件并假定它是您的默认操作系统代码页或 ANSI C。解析字符串时,它会将字符串解释为 ANSI C 字符串 1 字节 = 1 个字符。

为了解决这个问题,在 windows 下将 UTF-8 字符串转换为 UTF-16 并使用 wprintf 打印。目前没有对 Ascii/MBCS stdio 函数的原生 UTF-8 支持。

对于 Mac OS-X,它具有 UTF-8 的默认 OS 代码页,那么我建议遵循 Jonathan Leffler 解决问题的方法,因为它更优雅。虽然如果您稍后将其移植到 Windows,您会发现您需要使用下面的示例将字符串从 UTF-8 转换为 UTF-16。

在任一解决方案中,您仍然需要将命令提示符代码页更改为您的操作系统代码页,以正确打印 ASCII 以上的字符。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Windows.h>
#include <locale>

// File saved as UTF-8, with characters outside the ASCII range
int main()
{
    // Set the OEM code page to be the default OS code page
    setlocale(LC_ALL, "");

    // äö reside outside of the ASCII range and in the Unicode code point Western Latin 1
    // Thus, requires a lead byte per unicode code point when saving as UTF-8
    char* hmm = "äö";

    printf("UTF-8 file string using Windows 1252 code page read as:%s\n",hmm);
    printf("Length:%d\n", strlen(hmm));

    // Convert the UTF-8 String to a wide character
    int nLen = MultiByteToWideChar(CP_UTF8, 0,hmm, -1, NULL, NULL);
    LPWSTR lpszW = new WCHAR[nLen];
    MultiByteToWideChar(CP_UTF8, 0, hmm, -1, lpszW, nLen);

    // Print it
    wprintf(L"wprintf wide character of UTF-8 string: %s\n", lpszW); 

    // Free the memory
    delete[] lpszW;

    int c = getchar();
    return 0;
}


UTF-8 file string using Windows 1252 code page read as:äö
Length:4
wprintf wide character of UTF-8 string: äö
于 2012-12-30T07:17:47.333 回答
0

我会检查您的命令提示符字体/代码页,以确保它可以显示您的操作系统单字节编码。注意命令提示符有自己的代码页,与您的文本编辑器不同。

于 2012-12-29T16:48:12.210 回答