答疑解惑:开发者必须了解的Unicode和字符编码系统

news2025/3/5 4:46:49

目录

前言

ASCII

Unicode 

UTF-8

C#中的字符串类型

UTF-16

String.Length 返回的是字符个数吗?

问题与答案

总结

参考

前言

请大家先思考几个问题

  • 为什么有时候页面文本全是“锟斤拷”等乱码,有时候是个别字符别被替换为了�呢?
  • 有了解过ASCII, UTF-8, UTF-16, Latin1等字符集的设计原理与应用吗?
  • 开发过程中是否思考过字符串编码解码问题,文本都可以用UTF-8解码吗?
  • mysql默认字符集为什么是Latin1?
  • 网页,邮箱等互联网通信是如何确定内容的编码格式的?

请先不要着急知道答案,这篇博客不会从计算机编码系统历史讲起,也不会详细讲解每种编码方案的具体实现。

我会以尽量简洁的语言来描述计算机字符编码系统,以及和我们软件开发者的关系。

ASCII

相信每位开发者都知道ASCII。ASCII是一种早期基于拉丁语而设计的单字节编码方案,因此能表示的符号上限为256种。很明显,这种编码规则不能满足全世界人民的使用。

Unicode 

Unicode 是一种表达范围更广泛的国际编码标准。它拥有110多万个码位,几乎可以表示地球上所有语言系统, 码位是一个整数值,范围从 0 到 U+10FFFF(十进制 1,114,111), 除了汉字,日语等, 像 🌹 这种表情符号,𐱃 少见的突厥文字也都有对应的编码表示。

通常使用语法 U+xxxx 来表示码位,其中 xxxx 是十六进制编码的整数值。

整个码位范围包含两个子范围:

  • U+0000..U+FFFF 这个 16 位范围提供 65,536 个码位,足以涵盖世界上大多数编写系统。
  • U+10000..U+10FFFF 范围内的补充码位。 这个 21 位范围提供了超过一百万个额外的码位,可用于不太知名的语言和其他用途,例如表情符号。

UTF-8

但是最初很多人对Unicode的设计并不满意,因为世界上有很多软件是不需要考虑国际化的,尤其是英语国家,他们没有理由接受一种更复杂的编码方案,并且要花原先两倍的空间去存储“A, B, c, d...”。

后来出现的UTF-8成功的解决了这个问题,它是针对Unicode而设计的一种可变长度字符编码。

我们通过C#的方法来测试:可以看到字符“A” 经过UTF-8编码后得到的字节数是1,而汉字 “郭” 编码后的字节长度则是3。 

这一点我们通过查阅UTF-8详细的编码标准可以证实。

C#中的字符串类型

UTF-16

有传言说C#当中的字符串就是Unicode,这其实是一个非常容易混淆的概念,或许java, python等其它语言也有过类似的讨论。

Unicode只是将数字和字符逻辑映射的概念编码,它并没有指定字符是如何在计算机上存储的。

假如你不太理解这句话,我们接着往下看。

在认识字符串编码之前,我们需要清楚:C#中的string实际上是一种16位的值序列,也就是我们熟悉的char数组,1个char占有2个字节的空间。

在C#中使用Encoding.Unicode可以得到一个静态对象:以小端字节序获取UTF-16格式的编码器。

我们可以使用该编码器提供的Api,对常见的字符串进行编码测试。

我们下面来看段C#代码:

using System.Text;

var utf16 = Encoding.Unicode;

string str1 = "A";
Console.WriteLine($"{str1} Length={str1.Length}");
Console.WriteLine($"{str1} utf16:bytes={utf16.GetByteCount(str1)}");

这我们获取到:字符串“A” 经过utf-16编码得到的字节数组长度为2,这与使用UTF-8编码器得到的结果并不相同。

UTF-16也属于变长编码,也就是说并不是所有的符号编码后的字节长度都是2。比如:“🌹” 这种表情符号。 

String.Length 返回的是字符个数吗?

我们再来测试当一个C#字符串中包含特殊字符时,比如:🌹,字符串长度是多少

var utf16 = Encoding.Unicode;

//string str1 = "A";
//Console.WriteLine($"{str1} Length={str1.Length}");
//Console.WriteLine($"{str1} utf16:bytes={utf16.GetByteCount(str1)}");

string str2 = "🌹";
Console.WriteLine($"{str2} Length={str2.Length}, Length表示字符串中的char个数");
Console.WriteLine($"{str2} utf16:bytes={utf16.GetByteCount(str2)}");
标Windows控制台依然采用GDI+的方式渲染输出, 表情等特殊字符无法被渲染题

我们可以看到尽管第二个字符串只有一个🌹玫瑰符号,但string.Length的值却是2,这意味着它是两个char,占了四个字节。

这可能会给我们的开发工作带来一些问题,例如:当你将一个string当作char[] 进行处理时。

        最佳实践原则:在涉及字符串编码问题时,永远将字节流看作是一个整体进行操作。

不过,假如你必须对包含特殊符号的字符串进行逐字符的处理,那么你可以使用下面这种方法,使用StringInfo.GetTextElementEnumerator可以完整的识别出文本中的字符元素:

string str2 = "🌹";
Console.WriteLine($"{str2} Length={str2.Length}, Length表示字符串中的char个数");
Console.WriteLine($"{str2} utf16:bytes={utf16.GetByteCount(str2)}");

var enumerator = StringInfo.GetTextElementEnumerator(str2);
int lenght = 0;
while (enumerator.MoveNext())
{
    lenght++;
}
Console.WriteLine($"{str2} Element Length={lenght}");

问题与答案

那么,假如你理解了我上面所讲的内容,开头的那几个问题的答案大致也能想出来了。

1. 为什么有些时候页面文本全是“锟斤拷”等乱码,有些时候是个别字符别替换为了�呢?

答:当出现大面积乱码时,往往是因为编码和解码使用的方案不同。比如将文本通过GB2312编码,但解码时却是使用UTF-8,UTF-8就会将字节流以它的方式来解码,因此页面上就出现了乱码。而很多编码系统在字符集上是有重叠部分的,尤其是前127个用来表示英语字母的部分,因此假如你使用Latin1来编码一段英语文本,使用UTF-8来解码,大部分字符都将是正常的,但是127之后的特殊字符有可能就会解码失败。至于那些解码失败的字符是被替换成什么,或是是直接抛出异常,取决于具体的代码实现。

2. MySQL的默认编码为什么是Latin1?

答:Latin1编码范围使用了单字节内的所有空间。计算机最终存储的都将是字节序列流,而任何文本/字节流都可以被当作Latin1来编码/解码。

MySql默认编码是Latin1就是利用了这个特性。

3. 我能否在不知道编码方式的情况下对字符串进行解码?

答:因为每种人类语言都有不同的字母使用特征直方图,因此可以根据各种字节在各种语言的文本中出现的频率来猜测使用了哪种语言和编码,事实上IE浏览器就是这么做的。一些编程语言也提供了类似的api来做,但.NET并不支持这种模糊的做法。

4.如何在开发时解决可能出现的乱码问题?

答:约定。在Html最开始的地方约定当前网页的编码方案,当浏览器解析到编码方案时,会使用该方案重新解析。使用Http请求头中的Content-Type,XML中的encoding属性等。

总结

Unicode只是将数字和字符逻辑映射的概念编码,它并没有指定字符是如何在计算机上存储的。

所以问 “一个Unicode字符会占几个字节”是没有意义的。 

在Unicode官方资料中,Unicode的编码方式有三种:UTF-8、UTF-16、UTF-32。由于UTF-8与字节序无关,同时兼容ASCII编码,使得UTF-8编码成为现今互联网信息编码标准而被广泛使用,而C#中的string类型则默认使用了UTF-16。

到这里,我不知道有没有把字符编码系统的基本概念讲明白,但请记住最重要的一句话:

        无论在什么情况下,不清楚编码方式的字符串是没有意义的,计算机没有“纯文本”这种概念。

参考

The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!) – Joel on Software

Introduction to character encoding in .NET | Microsoft Learn

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/104157.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2.fs文件系统模块

fs模块是Node.js官方提供的用于操作文件的模块 目录 1 导入fs模块 2 读取文件内容 fs.readFile() 2.1 读取成功 2.2 读取失败 2.3 搞个函数判定读取成功还是失败 3 写入文件内容 fs.writeFile() 3.1 写入成功 3.2 写入失败 3.3 搞个函数判定写入成功还是失败…

如何构建企业内的 TiDB 自运维体系

1. 前言 得物 App 从创立之初,关系型数据库一直使用的开源数据库产品 MySQL。和绝大部分互联网公司一样,随着业务高速增长、数据量逐步增多,单实例、单库、单表出现性能瓶颈和存储瓶颈。从选型和架构设计角度来看这很符合发展规律&#xff0…

[思维模式-8]:《如何系统思考》-4- 认识篇 - 什么是系统思考?系统思考的特征?系统思考的思维转变。

目录 第1章 系统思考概述 1.1 什么是系统思考 1.2 系统思考适合解决什么样的问题?解决复杂问题的有效利器! 1.3 思维模式的转换:还原论向整体论(西医向中医) 第2章 系统思考的四项特征 2.1 看到全貌而非局部 2.…

ubuntu18.04+pycharm+pydesigner 配置教程(亲测可用)

文章目录系统环境pytorch 环境安装依赖包安装qtdesignerPyUICpycharm配置qtdesigner配置PyUIC配置成功如何使用参考文章:系统环境 ubuntu18.04 OS: Ubuntu 18.04.6 LTS Python version: 3.7 (64-bit runtime) Is CUDA available: True CUDA runtime version: 11.1…

物联网通信原理第4章 中远距离无线通信技术

目录 4.1 无线局域网(WLAN, Wireless LAN) 4.1.7 IEEE 802.11标准中的MAC子层(掌握) 1. IEEE 802.11 MAC帧格式 2. MAC层工作原理(本章重点) 4.4 无线局域网的扩频传输技术 4.4.1 直接序列扩频&#x…

使用inputmode改变移动端键盘弹出的类型

文章目录前言一、inputmode是什么?二、它有那些属性2.1 none2.2 text(默认值)2.3 numeric2.4 decimal2.5 tel2.6 search2.7 email2.8 url三、需要注意四、兼容前言 使用原因:需求是同时兼容移动端和PC端的输入,输入框数量多且绑定不同的对象…

深度学习Week11-调用官方权重进行检测(YOLOv5)

前言: 很早之前,我发过小白YOLOv5全流程-训练实现数字识别_牛大了2022的博客-CSDN博客_yolov5数字识别这篇文章,里面用简练语言分享用yolov5训练自己的识别器,但包括我在内许多人仍不了解其运行原理;过去两周&#xff…

Java并发——synchronized关键字

Java并发——synchronized关键字 1.synchronized作用的范围 synchronized有两种作用范围:对象锁和类锁 对象锁 使用方式: 在普通方法上加synchronized(默认锁对象为this)和同步代码块(自己指定锁对象) …

2022全年度净水器十大热门品牌销量榜单

随着人们健康意识的提升,每天喝足量水的观念已经深入人心,而伴随居民生活水平的提高,当下居民对水污染问题也更加关注,对饮水品质的认知和要求也随之升级。因此,净水器在过去几年开启了高速增长的趋势。 根据鲸参谋数据…

【AI with ML】第 14 章 :在 iOS 应用程序中使用 TensorFlow Lite

🔎大家好,我是Sonhhxg_柒,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流🔎 📝个人主页-Sonhhxg_柒的博客_CSDN博客 📃 🎁欢迎各位→点赞…

使用文档管理系统结束内容混乱

使用文档管理系统结束内容混乱 在我们目前所处的混合工作新环境中,数据和文档量快速增长而导致的“内容混乱”是效率和有效协作的常见障碍。管理这个问题可能是现代企业面临的最大挑战。 根据分析公司IDC发布的预测,2020年至2024年间创建的数据量将超过…

工控CTF之协议分析5——COTP

协议分析 流量分析 主要以工控流量和恶意流量为主,难度较低的题目主要考察Wireshark使用和找规律,难度较高的题目主要考察协议定义和特征 简单只能简单得干篇一律,难可以难得五花八门 常见的工控协议有:Modbus、MMS、IEC60870、…

PyTorch笔记 - MAE(Masked Autoencoders) PyTorch源码

欢迎关注我的CSDN:https://blog.csdn.net/caroline_wendy 本文地址:https://blog.csdn.net/caroline_wendy/article/details/128382935 Paper:MAE - Masked Autoencoders Are Scalable Vision Learners 掩码的自编码器是可扩展的视觉学习器 Kaiming He,FAIR Code:https://…

English Learning - L1-5 从此口语变得简约(上)2022.12.19 周一

English Learning - L1-5 从此口语变得简约(上)2022.12.19 周一6 非谓语动词6.1 建设非谓语的知道思相6.2 非谓语的三驾马车6.2.1 不定式做主语不定式自己的主语作宾语作补语特殊句型6.2.1 分词作状语作定语6 非谓语动词 6.1 建设非谓语的知道思相 总纲…

Pycharm下载与安装

今天继续给大家介绍Python相关知识,本文主要内容是Pycharm下载与安装。 一、Pycharm简介 Pycharm是一款Python集成开发环境,拥有项目管理、代码高亮、调试、智能提示等功能。Pycharm是由JetBrains公司打造,该公司官网主页URL为:…

python--Django框架

文章目录一、预备知识MVC和MTV模式二、Django框架启用后台admin站点管理项目的数据库模型自定义模型加入后台管理Django请求的生命周期一、预备知识 HTTP协议: ------超文本传输协议,基于TCP/IP;HTTP属于应用层的面向对象的协议 ------基于请…

MySQL#3(约束,数据库设计,多表查询,事务)

目录 一.约束 二.数据库设计 1.数据库设计的概念 2.数据库设计的步骤 3.表关系 三.多表查询 1.内连接和外连接 2.子查询 四.事务 1.简介 2.事务语法 3.事务四大特征 一.约束 1.约束的概念 约束是作用于表中列上的规则,用于限制加入表的数据约束的存在保证…

java-线程池

1、线程池的自我介绍: ● 线程的数量过多会反复的创建并销毁 ● 为什么使用线程池? ○ 第一:反复创建线程开销大 ○ 第二:过多的线程会占用太多内存 解决以上两个问题的思路: ○ 用少量的线程-避免内存占用过多 ○ 让这…

重磅干货!一文读懂「企业级架构」

本文来自: 刘剑桥 极狐(GitLab) 高级解决方案架构师 首先来看两个真实的小故事: 1 小 A 公司有 50 人,作为运维人员,小 A 为公司搭建了一个私有化 GitLab 社区版。 某日,开发同学发现不能够访问 GitLab 了。小 A 查…

Web3中文|随着世界杯结束,web3体育可能达到800亿美元

随着卡塔尔世界杯的结束,Web3 Studios发布了一份对web3体育的深度报道。它声称该行业正处于发展拐点,到2030年其规模有可能达到800亿美元。 该报告数据贡献者来自Animoca Brands、FaceIt、ConsenSys、The Football Company、Apex Capital、Upland、Loot…