gpt4 book ai didi

git - 为什么GIT本身不支持UTF-16

转载 作者:行者123 更新时间:2023-12-02 22:33:08 25 4
gpt4 key购买 nike

Git支持几种不同的编码方案:UTF-7UTF-8UTF-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个是非打印符号(控制代码0x000x1f,再加上0x7f代表DEL或已删除的打孔符)在纸带上,在此处以十六进制形式写入)。

当我们需要94个以上的可打印符号加空格(0x20)时,我们(我是说全世界使用计算机的人,而不仅仅是我)表示:好吧,看一下,我们有128种未使用的编码,< cc>到0x80,让我们使用其中的一些!因此,法语使用了ç和é等,以及诸如«和»的标点符号。捷克人需要一个带卡纸的Z z。俄罗斯人需要很多东西,用于西里尔字母。希腊人需要很多东西,依此类推。结果是8位空间的上半部分爆炸成许多不兼容的集合,人们称之为code pages

本质上,计算机存储了一些八位字节的值,例如235十进制(0xff十六进制),这取决于另一件事–另一个计算机程序,或者最终是人盯着屏幕,将235解释为,西里尔字母л或希腊字母λ等。如果使用的是代码页,它将告诉我们“ 235”的含义:我们应该对此施加什么样的语义。

这里的问题是我们可以支持多少个字符代码。如果我们想让西里尔字母L(л)与希腊字母L(lambda,λ)共存,就不能同时使用CP-1251和CP-1253,因此我们需要一种更好的方式来对符号进行编码。一种明显的方法是停止使用一个字节的值编码符号:如果使用两个字节的值,则可以编码65536个值,从0xEB0x0000;减去一些控制代码,仍然可以容纳许多字母。但是,我们甚至迅速突破了这个限制,因此我们使用了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范围内,因此可与一字节编码值区分开。 0x07ff0x0800范围内的代码点在相同的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只是存储字节。这些字节的含义取决于您。

当您运行0x00git 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,就像您当前可以声明文件.gitattributesbinary一样,它们都是可以解决的。这只是一团糟,还没有人做过这项工作。

脚注式:代码页可以被认为是(糟糕的)编码形式

上面我提到过,使用Unicode要做的事情是将21位代码点值编码为一定数量的8位字节(在UTF-8中为1到4个字节,在UTF-16中为2个字节,这是一个丑陋的小技巧)使用UTF-16的替代方法将21位值压缩到16位容器中,有时使用成对的16位值。这个编码技巧意味着我们可以表示所有合法的21位代码点值,尽管我们可能需要多个8位字节才能这样做。

当我们使用代码页(CP编号)时,我们正在做的就是,或至少可以将其视为将256个值(适合一个8位字节的值)映射到21位代码点空间中。我们挑选出不超过256个这样的代码点的子集,然后说:这些是我们允许的代码点。我们将第一个编码为text,第二个编码为0xa0,依此类推。我们总是留出至少一些控制代码的空间-通常在0xa10x00范围内的所有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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com