迭代具有非标准字符的char数组

时间:2012-12-29 16:37:35

标签: c arrays

修改 我只能使用stdio.h和stdlib.h

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

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

在我的例子中,char“ä”将使用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 个答案:

答案 0 :(得分:3)

char总是使用一个字节。

在你的情况下,你认为“ä”是一个字符:错误。 使用十六进制查看器打开.c源代码,您将看到ä正在使用2个char,因为该文件是以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;
}

答案 1 :(得分: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终端而言,正在打印的字节是无效的单字节。

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

答案 2 :(得分:1)

很抱歉将其拖动。虽然我认为重要的是突出一些问题。据我所知,OS-X能够将默认的操作系统代码页设置为UTF-8,因此答案主要针对引擎盖下使用UTF-16的Windows,其默认的ACP代码页依赖于指定的操作系统区域。

首先你可以打开角色地图,然后找到 AO

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

答案,使用
setlocale(LC_ALL,“”)

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

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

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

使用setlocal(LC_ALL,“”)跟踪Microsoft文档后,它详细说明了以下行为。

  

setlocale(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,我建议遵循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: äö

答案 3 :(得分:0)

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