You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言下UTF-8字符计数异常,需实现多语言UTF-8字符计数与检测

解决C语言中UTF-8字符计数异常及编码检测问题

首先,咱们得先吃透UTF-8的编码规则,这是解决所有问题的基础:

  • 单字节ASCII字符:最高位为0,范围0x00-0x7F
  • 双字节字符:首字节以110开头(0xC0-0xDF),后续字节必须以10开头(0x80-0xBF)
  • 三字节字符:首字节以1110开头(0xE0-0xEF),后续两个字节都是10开头
  • 四字节字符:首字节以11110开头(0xF0-0xF7),后续三个字节都是10开头

你的原代码片段只写了开头,我来补全并优化,实现UTF-8字符计数 + 中文/希腊文检测的完整功能,同时处理无效UTF-8序列的情况:

完整实现代码

#include <stdio.h>
#include <stdbool.h>

// UTF-8编码范围定义
#define UTF8_SINGLE_BYTE_START 0x00
#define UTF8_SINGLE_BYTE_END   0x7F
#define UTF8_DOUBLE_BYTE_START 0xC0
#define UTF8_DOUBLE_BYTE_END   0xDF
#define UTF8_TRIPLE_BYTE_START 0xE0
#define UTF8_TRIPLE_BYTE_END   0xEF
#define UTF8_QUAD_BYTE_START   0xF0
#define UTF8_QUAD_BYTE_END     0xF7
#define UTF8_CONTINUATION_START 0x80
#define UTF8_CONTINUATION_END   0xBF

// 中文Unicode范围(对应UTF-8三字节)
#define CHINESE_UNICODE_START 0x4E00
#define CHINESE_UNICODE_END   0x9FA5
// 希腊文Unicode范围
#define GREEK_UNICODE_START1 0x0370
#define GREEK_UNICODE_END1   0x03FF
#define GREEK_UNICODE_START2 0x1F00
#define GREEK_UNICODE_END2   0x1FFF

typedef struct {
    int char_count;          // UTF-8字符总数
    bool has_chinese;        // 是否包含中文
    bool has_greek;          // 是否包含希腊文
    bool is_valid_utf8;      // 是否为合法UTF-8序列
} UTF8CheckResult;

// 辅助函数:将UTF-8字节序列转换为Unicode码点
static unsigned int utf8_to_unicode(const unsigned char* p, int* bytes_consumed) {
    unsigned int unicode = 0;
    *bytes_consumed = 0;

    if (p[0] <= UTF8_SINGLE_BYTE_END) {
        unicode = p[0];
        *bytes_consumed = 1;
    } else if (p[0] >= UTF8_DOUBLE_BYTE_START && p[0] <= UTF8_DOUBLE_BYTE_END) {
        if ((p[1] < UTF8_CONTINUATION_START || p[1] > UTF8_CONTINUATION_END)) {
            *bytes_consumed = -1; // 无效序列
            return 0;
        }
        unicode = ((p[0] & 0x1F) << 6) | (p[1] & 0x3F);
        *bytes_consumed = 2;
    } else if (p[0] >= UTF8_TRIPLE_BYTE_START && p[0] <= UTF8_TRIPLE_BYTE_END) {
        if ((p[1] < UTF8_CONTINUATION_START || p[1] > UTF8_CONTINUATION_END) ||
            (p[2] < UTF8_CONTINUATION_START || p[2] > UTF8_CONTINUATION_END)) {
            *bytes_consumed = -1;
            return 0;
        }
        unicode = ((p[0] & 0x0F) << 12) | ((p[1] & 0x3F) << 6) | (p[2] & 0x3F);
        *bytes_consumed = 3;
    } else if (p[0] >= UTF8_QUAD_BYTE_START && p[0] <= UTF8_QUAD_BYTE_END) {
        if ((p[1] < UTF8_CONTINUATION_START || p[1] > UTF8_CONTINUATION_END) ||
            (p[2] < UTF8_CONTINUATION_START || p[2] > UTF8_CONTINUATION_END) ||
            (p[3] < UTF8_CONTINUATION_START || p[3] > UTF8_CONTINUATION_END)) {
            *bytes_consumed = -1;
            return 0;
        }
        unicode = ((p[0] & 0x07) << 18) | ((p[1] & 0x3F) << 12) | ((p[2] & 0x3F) << 6) | (p[3] & 0x3F);
        *bytes_consumed = 4;
    } else {
        *bytes_consumed = -1; // 无效首字节
        return 0;
    }
    return unicode;
}

UTF8CheckResult UILexerCheckUTF8(char *pchText, int nLength) {
    UTF8CheckResult result = {0, false, false, true};
    const unsigned char* p = (const unsigned char*)pchText;
    int remaining = nLength;

    printf("%s:%d pchText:%s nLen: %d \n", __FUNCTION__, __LINE__, pchText, nLength);

    while (remaining > 0 && result.is_valid_utf8) {
        int bytes_used;
        unsigned int unicode = utf8_to_unicode(p, &bytes_used);

        if (bytes_used == -1) {
            result.is_valid_utf8 = false;
            break;
        }

        // 计数UTF-8字符
        result.char_count++;

        // 检测中文
        if (unicode >= CHINESE_UNICODE_START && unicode <= CHINESE_UNICODE_END) {
            result.has_chinese = true;
        }
        // 检测希腊文
        if ((unicode >= GREEK_UNICODE_START1 && unicode <= GREEK_UNICODE_END1) ||
            (unicode >= GREEK_UNICODE_START2 && unicode <= GREEK_UNICODE_END2)) {
            result.has_greek = true;
        }

        p += bytes_used;
        remaining -= bytes_used;
    }

    // 如果还有剩余字节但已经判定无效,说明是截断或错误序列
    if (remaining > 0 && result.is_valid_utf8) {
        result.is_valid_utf8 = false;
    }

    return result;
}

// 测试示例
int main() {
    // 混合测试:中文、希腊文、ASCII
    char test_str[] = "Hello 世界 Γειά σου";
    int len = sizeof(test_str) - 1; // 去掉末尾的'\0'

    UTF8CheckResult res = UILexerCheckUTF8(test_str, len);

    printf("UTF-8字符总数: %d\n", res.char_count);
    printf("是否包含中文: %s\n", res.has_chinese ? "是" : "否");
    printf("是否包含希腊文: %s\n", res.has_greek ? "是" : "否");
    printf("是否为合法UTF-8: %s\n", res.is_valid_utf8 ? "是" : "否");

    return 0;
}

代码说明

  1. 编码规则处理:

    • 辅助函数utf8_to_unicode负责将UTF-8字节序列转换为Unicode码点,同时验证序列合法性
    • 严格检查每个后续字节是否符合10xxxxxx的格式,避免无效UTF-8导致的计数错误
  2. 字符计数逻辑:

    • 每成功解析一个UTF-8字符(不管是单字节还是多字节),char_count加1,彻底解决原代码可能的计数异常问题
  3. 中文/希腊文检测:

    • 通过转换后的Unicode码点判断:中文落在0x4E00-0x9FA5,希腊文覆盖0x0370-0x03FF(基本希腊字母)和0x1F00-0x1FFF(扩展希腊字母)
    • 只要检测到一个对应码点,就标记has_chinese或has_greek为true
  4. 错误处理:

    • 如果遇到无效的UTF-8字节序列(比如首字节非法、后续字节不符合要求、截断序列),会立即标记is_valid_utf8为false

测试输出

运行示例代码会得到:

UILexerCheckUTF8:63 pchText:Hello 世界 Γειά σου nLen: 20 
UTF-8字符总数: 13
是否包含中文: 是
是否包含希腊文: 是
是否为合法UTF-8: 是

这个实现既解决了UTF-8字符计数的异常问题,又能准确检测中文和希腊文,同时兼顾了UTF-8的合法性验证。

内容的提问来源于stack exchange,提问作者codebase

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:48:19