如何比较C中的多字节字符

时间:2015-11-16 14:31:55

标签: c compare

我尝试解析文本并在其中找到一些字符。我使用下面的代码。它适用于 Dictionary<string, int> friendsGained = latestTwo[0].names.Subtract(latestTwo[1].names); Dictionary<string, int> friendsLost = latestTwo[1].names.Subtract(latestTwo[0].names); 等普通字符,但不适用于abcdef。 GCC提供编译警告。我应该怎样做才能使用öçşğüı

代码:

öçşğüı

警告:

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

int main()
{
    char * text = "öçşğü";
    int i=0;

    text = strdup(text);

    while (text[i])
    {       
        if(text[i] == 'ö')
        {
            printf("ö \n");
        }

        i++;
    }

    return 0;
}

在while循环中打印char的地址时有10个地址

warning: multi-character character constant [-Wmultichar]
warning: comparison is always false due to limited range of data type [-Wtype-limits]

输出:

printf("%d : %p \n", i, text[i]);

0 : 0xffffffc3 1 : 0xffffffb6 2 : 0xffffffc3 3 : 0xffffffa7 4 : 0xffffffc5 5 : 0xffffff9f 6 : 0xffffffc4 7 : 0xffffff9f 8 : 0xffffffc3 9 : 0xffffffbc 为10。

但如果我使用strlen

abcde

0 : 0x61 1 : 0x62 2 : 0x63 3 : 0x64 4 : 0x65 为5。

如果我使用strlen进行文字输出

wchar_t

0 : 0xa7c3b6c3 1 : 0x9fc49fc5 2 : 0xbcc3 为10,strlen为3。

4 个答案:

答案 0 :(得分:1)

要浏览字符串中的每个字符,可以使用mblen。您还需要设置正确的语言环境(由多字节字符串表示的编码),以便mblen可以正确解析多字节字符串。

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

int main()
{
    char * text = "öçşğü";
    int i=0, char_len;

    setlocale(LC_CTYPE, "en_US.utf8");

    while ((char_len = mblen(&text[i], MB_CUR_MAX)) > 0)
    {
        /* &text[i] contains multibyte character of length char_len */
        if(memcmp(&text[i], "ö", char_len) == 0)
        {
            printf("ö \n");
        }

        i += char_len;
    }

    return 0;
}

有两种类型的字符串表示,使用多字节(8位字节)或宽字节(大小取决于平台)。多字节表示具有可以使用char *(代码中常用的c字符串)表示的优点,但缺点是多个字节表示字符。宽字符串使用wchar_t *表示。 wchar_t的优点是一个wchar_t是一个字符(但正如@anatolyg指出的那样,在wchar_t无法表示所有可能字符的平台上,这个假设仍然可能出错。)

您是否使用十六进制编辑器查看了源代码?字符串"öçşğü"实际上由内存中的多字节字符串c3 b6 c3 a7 c5 9f c4 9f c3 bc表示(UTF-8编码),当然零终止。您只看到5个字符,因为您的UTF-8感知查看器/浏览器正确呈现了字符串。很容易意识到strlen(text)为此返回10,而上面的代码只循环5次。

如果使用宽字节字符串,可以按照@WillBriggs的说明完成。

答案 1 :(得分:0)

没有关于在源文件中直接嵌入非ASCII字符的标准。

相反,C11标准指定您可以使用Unicode代码点:

wchar_t text[] = L"\u00f6\u00e7\u015f\u0131\u011f";

// Print whole string
wprintf(L"%s\n", text);

// Test individual characters
for (size_t i = 0; text[i]; ++i)
{
    if ( text[i] == u'\u00f6' )
        // whatever...
}

如果您在Windows中,那么您将遇到一个额外的问题,即Windows控制台默认情况下无法打印Unicode字符。您需要执行以下操作:

  • 更改控制台以使用TrueType等宽字体,其中包含您要打印的字符的字形。 (我在这个例子中使用了“DejaVu Sans Mono”)
  • 在源代码中,调用_setmode(1, _O_WTEXT);函数,该函数需要#include <fcntl.h>

要恢复正常文字,您可以_setmode(1, _O_TEXT);

当然,如果您要输出到文件或Win32 API函数,那么您不需要执行这些步骤。

答案 2 :(得分:0)

请参阅此处的wiki:https://en.wikipedia.org/wiki/UTF-8特别是,有一个包含位模式的表。

以下是将utf-8字符串扫描/转换为"IsRead"的另一种方式[不完全,只是一个示例 - 请参阅wiki]:

codepoint

答案 3 :(得分:-1)

处理宽字符的最佳方法是宽字符。

wchar_t myWord[] = L"Something";

这样做:

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

int main()
{
    wchar_t * text = L"öçşğü";
    int i = 0;

    while (text[i])
    {
        if (text[i] == L'ö')
        {
            wprintf(L"ö \n");
        }

        i++;
    }

    return 0;
}

如果你像我一样在Visual Studio中,请回想一下控制台窗口不能很好地处理Unicode。您可以将其重定向到文件并检查文件,然后查看ö