簡體   English   中英

如何在C中比較多字節字符

[英]How to compare multibyte characters in C

我嘗試解析文本並在其中找到一些字符。 我使用下面的代碼。 它適用於諸如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;
}

警告 :

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

在while循環中打印char的地址時,有10個地址

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 

strlen是10

但是,如果我使用abcde

0 : 0x61 
1 : 0x62 
2 : 0x63 
3 : 0x64 
4 : 0x65 

strlen是5。


如果我使用wchar_t進行文本輸出是

0 : 0xa7c3b6c3 
1 : 0x9fc49fc5 
2 : 0xbcc3 

strlen是10, wcslen是3。

要遍歷字符串中的每個字符,可以使用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的說明進行操作。

沒有標准可直接在源文件中嵌入非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函數,則無需執行這些步驟。

參見Wiki: https//zh.wikipedia.org/wiki/UTF-8特別是,其中有一張帶有位模式的表格。

這是將utf-8字符串掃描/轉換為codepoint的另一種方法[不完全是,只是一個示例-請參閱Wiki]:

// utf8scan -- convert utf8 to codepoints (example)

char inpbuf[1000];
char uni[8];

typedef union {
    char utf8[4];
    unsigned int code;
} codepoint_t;

codepoint_t outbuf[1000];

// unidecode -- decode utf8 char into codepoint
// RETURNS: updated rhs pointer
char *
unidecode(codepoint_t *lhs,char *rhs)
{
    int idx;
    int chr;

    idx = 0;
    lhs->utf8[idx++] = *rhs++;

    for (;  ;  ++rhs, ++idx) {
        chr = *rhs;

        // end of string
        if (chr == 0)
            break;

        // start of new ascii char
        if ((chr & 0x80) == 0)
            break;

        // start of new unicode char
        if (chr & 0x40)
            break;

        lhs->utf8[idx] = chr;
    }

    return rhs;
}

// main -- main program
int
main(void)
{
    char *rhs;
    codepoint_t *lhs;

    rhs = inpbuf;
    lhs = outbuf;

    for (;  *rhs != 0;  ++lhs) {
        lhs->code = 0;

        // ascii char
        if ((*rhs & 0x80) == 0)
            lhs->utf8[0] = *rhs++;

        // get/skip unicode char
        else
            rhs = unidecode(lhs,rhs);
    }

    // add EOS
    lhs->code = 0;

    return 0;
}

處理寬字符的最佳方法就是寬字符。

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。 您可以將其重定向到文件並檢查文件,然后查看ö

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM