字符集与字符编码

本文介绍了字符集与字符编码的概念,强调Unicode是字符集,而UTF-8、UTF-16、UTF-32是其编码方式。解释了各编码的长度特点,如UTF-8的变长编码,UTF-16的2或4字节。还提到了在MySQL中使用utf8mb4以支持完整的UTF-8编码,以及在nginx配置中的charset设置。此外,通过代码示例展示了如何进行字符集转换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先弄懂什么是字符集,什么是字符编码。

区别和联系

字符集是多个字符的集合,可以理解为二进制数,与字符的映射关系,唯一的一个编号就代表一个字。
字符编码是计算机中对字符的表示方式。
字符集与字符编码可以这样区分:
1.字符集是书写系统字母与符号的集合。
2.字符编码则是将字符映射为一特定的字节或字节序列,是一种规则。

Unicode和UTF

Unicode是字符集,utf-8、utf-16、utf-32是编码方式。这一点要注意区分。utf编码要先转成unicode再显示。这里不会讲解每个编码方式的具体细节,只是提示一些问题。

编码长度

utf-8是变长编码,大小为1~6B,可以理解为是类似base128的编码方式,通过前缀码进行识别。
utf-16是2个字节或4个字节。处在不同unicode编码范围上的值会有不同的长度。
utf-32是固定4个字节。

大小端问题

在文件的开头会有文件头标识BOM,用以区分大小端的编码方式。
utf-8是EF BB BF,注意utf-8默认大端,默认缺省不带BOM。
utf-16LE是小端的编码方式,文件头标识是FF FE。utf-16BE是大端的编码方式,标识是FE FF。UTF-32LE是FF FE 00 00。UTF-32BE是00 00 FE FF。linux中可以通过file -i命令查看文件的编码方式。

使用上的问题

1.mysql的utf-8编码
这是一个历史遗留问题,mysql中的"utf8"不是真正的utf-8编码方式,只支持最大3个字节,要想使用真正的utf-8编码,需用"utf8mb4"。

CREATE TABLE tbl ( id INT UNSIGNED AUTO_INCREMENT, 
                  utf8mb4_title VARCHAR(100) NOT NULL,    
                  PRIMARY KEY (utf8mb4_id)            
                 )ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

2.nginx配置字符串
需在conf文件对应位置加上一行charset utf-8;

server 
{
    listen  8888;
    charset utf-8;
    # ip地址或者域名
    server_name 0.0.0.0;
    location / 
    {
        # web页面所在目录
	    root /mnt/hgfs/unicode-zip-src/unicode/nginx;
        index index.php index.html index.htm;
    }
}

字符集转换编码

这里直接贴出一段使用的代码,相应的转换函数功能通过注释进行说明。

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

int main(int argc, char **argv)
{
    unsigned char *encTo = "UTF-16";
    /* 源编码 */
    unsigned char *encFrom = "UTF-8";

    /* 获得转换句柄
   *@param encTo 目标编码方式
   *@param encFrom 源编码方式
   *
   * */
    iconv_t cd = iconv_open(encTo, encFrom);
    if (cd == (iconv_t)-1)
    {
        perror("iconv_open");
    }
    /* 需要转换的字符串 */
    unsigned char inbuf[1024] = "转换AB79字cd符串"; // 21
    size_t srclen = strlen(inbuf);
    /* 打印需要转换的字符串的长度 */
    printf("srclen=%ld\n", srclen);
    /* 存放转换后的字符串 */
    size_t outlen = 1024;
    unsigned char outbuf[outlen];
    size_t utf16_len = outlen;
    memset(outbuf, 0, outlen);
    /* 由于iconv()函数会修改指针,所以要保存源指针 */
    unsigned char *srcstart = inbuf;
    unsigned char *tempoutbuf = outbuf;
    printf("utf8:\n");
    for (int i = 0; i < strlen(inbuf); i++)
    {
        printf("%02x ", inbuf[i]);
    }
    printf("\n");

    /* 进行转换
   *@param cd iconv_open()产生的句柄
   *@param srcstart 需要转换的字符串
   *@param srclen 存放还有多少字符没有转换
   *@param tempoutbuf 存放转换后的字符串
   *@param outlen 存放转换后,tempoutbuf剩余的空间
   *
   * */
    //outlen = 20;
    printf("1 srcstart=%p, tempoutbuf=%p, srclen=%ld, outlen=%ld\n",
           srcstart, tempoutbuf, srclen, outlen);
    size_t ret = iconv(cd, (char **)&srcstart, &srclen, (char **)&tempoutbuf, &outlen);
    printf("2 srcstart=%p, tempoutbuf=%p, srclen=%ld, outlen=%ld\n",
           srcstart, tempoutbuf, srclen, outlen);

    if (ret == -1)
    {
        perror("iconv");
    }
    utf16_len = utf16_len - outlen;
    printf("inbuf=%s, srclen=%ld, outbuf=%s, outlen=%ld,  ret = %ld\n",
           inbuf, srclen, outbuf, utf16_len, ret);

    printf("utf16:\n");
    for (int i = 0; i < utf16_len; i++)
    {
        printf("%02x ", outbuf[i]);
    }
    printf("\n");
    /* 关闭句柄 */
    iconv_close(cd);

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值