- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
Git支持几种不同的编码方案:UTF-7
,UTF-8
,UTF-32
以及非UTF编码方案。
鉴于此,为什么它不支持UTF-16
?
有很多问题询问如何获取git以支持UTF-16,但是我认为这还没有被明确地提出或回答。
最佳答案
我将我(当前相当垂死)book (see Chapter 3, which is in better shape than later chapters)整章中的很大一部分专门用于字符编码问题,因为这是一个历史性的混乱。不过,在这里值得一提的是,这个问题的前提的一部分(Git以某种方式支持UTF-7和UTF-32)是错误的:UTF-7 is a standard that never even came about并且可能永远都不要使用(自然地,较旧的Internet资源管理器版本确实存在,这会导致在链接的维基百科页面上提到的安全性问题。
就是说,让我们首先将字符编码与代码页分开。 (也请参见下面的脚注部分。)这里的根本问题是,计算机(无论如何还是现代的)都可以处理一系列8位字节,每个字节代表[0..255]范围内的整数。 。较旧的系统具有6、7、8甚至9位字节,尽管我认为将少于8位的任何内容称为“字节”都是令人误解的。 (BBN的“ C机器”有10位字节!)在任何情况下,如果一个字节代表一个字符符号,则我们可以得到256种符号的上限。在ASCII的那段糟糕的过去,这已经足够了,因为ASCII只有128个符号,其中33个是非打印符号(控制代码0x00
至0x1f
,再加上0x7f
代表DEL或已删除的打孔符)在纸带上,在此处以十六进制形式写入)。
当我们需要94个以上的可打印符号加空格(0x20
)时,我们(我是说全世界使用计算机的人,而不仅仅是我)表示:好吧,看一下,我们有128种未使用的编码,< cc>到0x80
,让我们使用其中的一些!因此,法语使用了ç和é等,以及诸如«和»的标点符号。捷克人需要一个带卡纸的Z z。俄罗斯人需要很多东西,用于西里尔字母。希腊人需要很多东西,依此类推。结果是8位空间的上半部分爆炸成许多不兼容的集合,人们称之为code pages。
本质上,计算机存储了一些八位字节的值,例如235十进制(0xff
十六进制),这取决于另一件事–另一个计算机程序,或者最终是人盯着屏幕,将235解释为,西里尔字母л或希腊字母λ等。如果使用的是代码页,它将告诉我们“ 235”的含义:我们应该对此施加什么样的语义。
这里的问题是我们可以支持多少个字符代码。如果我们想让西里尔字母L(л)与希腊字母L(lambda,λ)共存,就不能同时使用CP-1251和CP-1253,因此我们需要一种更好的方式来对符号进行编码。一种明显的方法是停止使用一个字节的值编码符号:如果使用两个字节的值,则可以编码65536个值,从0xEB
到0x0000
;减去一些控制代码,仍然可以容纳许多字母。但是,我们甚至迅速突破了这个限制,因此我们使用了Unicode,它可以容纳1,114,112个称为code points的空间,每个Unicode都代表某种具有某种语义的符号。现在大约使用了100,000多个,包括😀和like等表情符号。
将Unicode编码为字节或字
这是UTF-8,UTF-16,UTF-32,UCS-2和UCS-4都加入的地方。这些都是将Unicode代码点(这大约一百万个值之一)编码为字节流的方案。我将完全跳过UCS编码,而仅看一下UTF-8和UTF-16编码,因为这是目前最有趣的两种。 (另请参见What is Unicode, UTF-8, UTF-16?)
UTF-8编码很简单:十进制值小于128的任何代码点都被编码为包含该值的字节。这意味着普通ASCII文本字符保留为普通ASCII文本字符。 0xffff
(十进制128个十进制)到0x0080
(十进制2047个)中的代码点编码为两个字节,它们的值都在128-255范围内,因此可与一字节编码值区分开。 0x07ff
至0x0800
范围内的代码点在相同的128-255范围内编码为三个字节,其余有效值编码为四个此类字节。就Git本身而言,此处的关键是没有编码值类似于ASCII NUL(0xffff
)或斜杠(0x00
)。
这种UTF-8编码的作用是让Git假装文本字符串(尤其是文件名)是用斜杠分隔的名称组件,它们的结尾都或者可以用ASCII NUL字节标记。这是Git在树对象中使用的编码,因此UTF-8编码的树对象正好适合,而无需摆弄。
UTF-16编码每个字符使用两个成对的字节。对于Git和路径名,这有两个问题。首先,一对中的一个字节可能会意外地类似于0x2f
,并且所有ASCII值字符必须编码为一对字节,其中一个字节为/
,类似于ASCII NUL。因此,Git需要知道:此路径名已使用UTF-16进行编码,并且适用于字节对。树对象中没有空间供此信息使用,因此Git需要一个新的对象类型。其次,每当将16位值分成两个单独的8位字节时,我们都会以某种顺序执行此操作:我要么先给您更高的有效字节,然后再给您较低的字节;或者我先给您低位字节,然后给您高位字节。第二个问题导致UTF-16具有Byte Order Marks的原因。 UTF-8不需要字节顺序标记就足够了,那么为什么不在树中使用它呢? Git也是如此。
对树来说很好,但是我们也有提交,标签和斑点
Git对这四种对象中的三种做自己的解释:
提交包含哈希ID。
树包含路径名,文件模式和哈希ID。
标签包含哈希ID。
这里未列出的是blob,并且在大多数情况下,Git不会对blob进行任何解释。
为了易于理解提交,树和标签,Git在大多数情况下将所有三个约束都限制在UTF-8中。但是,Git确实允许提交中的日志消息或标签中的标签文本在某种程度上(大部分)是未解释的。它们位于Git解释的标头之后,因此,即使此时有些特别棘手或丑陋的事情,也很安全。 (这里存在一些较小的风险,因为出现在标题下方的PGP签名确实会被解释。)特别是对于提交,现代Git将在解释部分中包含编码标题行,然后Git可以尝试对提交消息进行解码主体,然后将其重新编码为解释Git吐出的字节的任何程序使用的任何编码。1
相同的规则可用于带注释的标记对象。我不确定Git是否具有对标签执行此操作的代码(大多数情况下都可以重复使用提交代码,但是标签更常见的是具有PGP签名,因此在此处强制使用UTF-8可能更明智)。由于树是内部对象,因此它们的编码在任何情况下都是不可见的-您无需意识到这一点(我在书中指出的问题除外)。
这留下斑点,是大猩猩。
1这是计算世界中经常出现的主题:重复编码和解码所有内容。考虑一下某些东西是如何通过WiFi或电缆网络连接到达的:它被编码为某种无线电波或类似的无线电波,然后某些硬件将其解码为比特流,然后其他一些硬件将其重新编码为字节流。硬件和/或软件剥离标题,以某种方式解释其余的编码,适当地更改数据,并对位和字节重新编码,以供另一层硬件和软件处理。一切都完成了,真是一个奇迹。
斑点编码
Git喜欢声称它完全与文件中存储的实际数据无关,就像Git斑点一样。甚至大部分都是如此。或者,好吧,一半正确。或者其他的东西。只要Git所做的一切就是存储您的数据,那是完全正确的! Git只是存储字节。这些字节的含义取决于您。
当您运行0x00
或git diff
时,这个故事会分崩离析,因为diff算法以及合并代码都是面向行的。行以换行符终止。 (如果您使用的是CRLF而不是换行符的系统,那么CRLF对的第二个字符是换行符,因此这里没有问题-Git可以使用不终止的最后一行,尽管这会导致一些次要问题如果文件使用UTF-16编码,则很多字节似乎是ASCII NUL,因此Git只是将其视为二进制。
这是可修复的:Git可以将UTF-16数据解码为UTF-8,通过其所有现有的面向行的算法(现在将看到换行符结束的行)提供该数据,然后将数据重新编码回UTF -16。这里有很多较小的技术问题。最大的决定是确定某个文件是UTF-16,如果是,则确定哪个字节序(UTF-16-LE或UTF-16-BE?)。如果文件具有字节顺序标记,则可以解决字节序问题,并且可以将UTF-16-ness编码为git merge
,就像您当前可以声明文件.gitattributes
或binary
一样,它们都是可以解决的。这只是一团糟,还没有人做过这项工作。
脚注式:代码页可以被认为是(糟糕的)编码形式
上面我提到过,使用Unicode要做的事情是将21位代码点值编码为一定数量的8位字节(在UTF-8中为1到4个字节,在UTF-16中为2个字节,这是一个丑陋的小技巧)使用UTF-16的替代方法将21位值压缩到16位容器中,有时使用成对的16位值。这个编码技巧意味着我们可以表示所有合法的21位代码点值,尽管我们可能需要多个8位字节才能这样做。
当我们使用代码页(CP编号)时,我们正在做的就是,或至少可以将其视为将256个值(适合一个8位字节的值)映射到21位代码点空间中。我们挑选出不超过256个这样的代码点的子集,然后说:这些是我们允许的代码点。我们将第一个编码为text
,第二个编码为0xa0
,依此类推。我们总是留出至少一些控制代码的空间-通常在0xa1
到0x00
范围内的所有32个代码-通常我们会像Unicode本身一样保留整个7位ASCII子集(请参见https://en.wikipedia.org/wiki/List_of_Unicode_characters),这就是为什么我们最通常从0x1f
开始的原因。
当人们编写适当的Unicode支持库时,仅使用这种形式的索引就可以将代码页简单地转换为转换表。困难的部分是为所有代码页创建准确的表,其中有很多代码页。
关于代码页的好处是,每个字符又是一个字节。不好的是,当您说:我使用此代码页时,只需选择一次符号集。从那时起,您就被锁定在Unicode的这一小部分中。如果切换到另一个代码页,则部分或全部八位字节值表示不同的符号。
关于git - 为什么GIT本身不支持UTF-16,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52472435/
UTF-8、UTF-16 和 UTF-32 之间有何区别? 据我所知,它们都将存储 Unicode,并且每个都使用不同数量的字节来表示字符。选择其中之一是否有优势? 最佳答案 当 ASCII 字符代表
好的。我知道这看起来像典型的“他为什么不直接用谷歌搜索或去 www.unicode.org 查一下?”问题,但对于这样一个简单的问题,在检查了两个来源后,我仍然无法回答。 我很确定这三种编码系统都支持
是否存在可以用 UTF-16 编码但不能用 UTF-8 编码的字符 最佳答案 没有。 UTF-* 是可以对全范围 Unicode 字符进行编码的编码。 编码之间的差异在于每个字符使用多少字节。 关于u
是否存在可以用 UTF-16 编码但不能用 UTF-8 编码的字符 最佳答案 没有。 UTF-* 是可以对全范围 Unicode 字符进行编码的编码。 编码之间的差异在于每个字符使用多少字节。 关于u
UTF-16 是一种双字节字符编码。交换两个字节的地址将产生 UTF-16BE 和 UTF-16LE。 但我发现在 Ubuntu gedit 文本编辑器中存在名称 UTF-16 编码,以及 UTF-1
我想将 UTF-16 字符串转换为 UTF-8。我通过 Unicode 发现了 ICU 库。我在转换时遇到问题,因为默认设置是 UTF-16。我试过使用转换器: UErrorCode myError
UTF-16 需要 2 个字节,UTF-8 需要 1 个字节。 而USB是面向8bit的,UTF-8更自然。 UTF-8 向后兼容 ASCII,而 UTF-16 则不然。 UTF-16 需要 2 个字
我对将 unicode 字符转换为十六进制值有点困惑。 我正在使用这个网站获取字符的十六进制值。 ( https://www.branah.com/unicode-converter ) 如果我输入“
我已经用UTF-8编码创建了一个文件,但是我不了解其在磁盘上占用的大小的规则。这是我的完整研究: 首先,我创建了一个带有印地语字母“'”的文件,Windows 7上的文件大小为 8个字节。 现在带有两
如何将WideString(或其他长字符串)转换为UTF-8中的字节数组? 最佳答案 这样的功能将满足您的需求: function UTF8Bytes(const s: UTF8String): TB
我有一个奇怪的验证程序,用于验证utf-8字符串是否是有效的主机名(PHP中的Zend Framework主机名valdiator)。它允许IDN(国际化域名)。它将比较每个子域与由其十六进制字节表示
在 utf16 和 utf32 中,一个字节的零是否意味着空?就像在 utf8 中一样,还是我们需要 2 个和 4 个字节的零来相应地在 utf16 和 utf32 中创建 null? 最佳答案 在
这是基于我的观察,对于 mysql,默认字符集 utf8 有点误导,它不支持完整的 Unicode,因为它无法存储四字节 UTF-8 编码的字符。它实际上是 utf8mb4 字符集,它是完整的 Uni
我只有处理 ASCII(单字节字符)的经验,并且阅读了很多关于人们如何以不同方式处理 Unicode 的帖子,这些帖子提出了他们自己的一系列问题。 此时我对 Unicode 的了解非常有限,我读到过U
我明白 std::codecvt在 C++11 中执行 UTF-16 和 UTF-8 之间的转换,并且 std::codecvt执行 UTF-32 和 UTF-8 之间的转换。是否可以在 UTF-8
我正在编写一个 HTTP 服务器并使用 trivial-utf-8:write-utf-8-bytes 来响应请求。我听说Babel就像trivial-utf-8但效率更高,所以我想试一试。搜索了一段
我正在设计一个新的 CMS,但想要设计它来满足我 future 的所有需求,比如多语言内容,所以我认为 Unicode (UTF-8) 是最好的解决方案 但是通过一些搜索我得到了这篇文章 http:/
例如,假设我在字符串中有以下 xml: 如果我尝试将其插入到带有 Xml 列的 SQL Server 2005 数据库表中,我将收到以下错误(我使用的是 EF 4.1,但我认为这无关紧要): XM
我正在使用 Python CSV 库读取两个 CSV 文件。 一种使用 UTF-8-BOM 编码,另一种使用 UTF-8 编码。在我的实践中,我发现使用“utf-8-sig”作为编码类型可以读取这两个
假设我的数据库设置如下以使用 utf-8(mysql 中的完整 4mb 版本) mysql_query("SET CHARACTER SET utf8mb4"); mysql_query("SET N
我是一名优秀的程序员,十分优秀!