This commit is contained in:
krahets
2025-07-10 07:14:51 +08:00
parent ea4ae128df
commit 4045471c84
349 changed files with 15161 additions and 15092 deletions
@@ -62,17 +62,15 @@
<link href="../../assets/stylesheets/glightbox.min.css" rel="stylesheet"/><style>
html.glightbox-open { overflow: initial; height: 100%; }
.gslide-title { margin-top: 0px; user-select: text; }
.gslide-desc { color: #666; user-select: text; }
.gslide-image img { background: white; }
.gscrollbar-fixer { padding-right: 15px; }
.gdesc-inner { font-size: 0.75rem; }
body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);}
body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);}
body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}
</style> <script src="../../assets/javascripts/glightbox.min.js"></script></head>
html.glightbox-open { overflow: initial; height: 100%; }
.gslide-title { margin-top: 0px; user-select: text; }
.gslide-desc { color: #666; user-select: text; }
.gslide-image img { background: white; }
.gscrollbar-fixer { padding-right: 15px; }
.gdesc-inner { font-size: 0.75rem; }
body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);}
body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);}
body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}</style> <script src="../../assets/javascripts/glightbox.min.js"></script></head>
@@ -1001,7 +999,7 @@
<li class="md-nav__item">
<a href="#341-ascii" class="md-nav__link">
<span class="md-ellipsis">
3.4.1 &nbsp; ASCII 字
3.4.1 &nbsp; ASCII 字
</span>
</a>
@@ -1010,7 +1008,7 @@
<li class="md-nav__item">
<a href="#342-gbk" class="md-nav__link">
<span class="md-ellipsis">
3.4.2 &nbsp; GBK 字
3.4.2 &nbsp; GBK 字
</span>
</a>
@@ -1019,7 +1017,7 @@
<li class="md-nav__item">
<a href="#343-unicode" class="md-nav__link">
<span class="md-ellipsis">
3.4.3 &nbsp; Unicode 字
3.4.3 &nbsp; Unicode 字
</span>
</a>
@@ -3567,7 +3565,7 @@
<li class="md-nav__item">
<a href="#341-ascii" class="md-nav__link">
<span class="md-ellipsis">
3.4.1 &nbsp; ASCII 字
3.4.1 &nbsp; ASCII 字
</span>
</a>
@@ -3576,7 +3574,7 @@
<li class="md-nav__item">
<a href="#342-gbk" class="md-nav__link">
<span class="md-ellipsis">
3.4.2 &nbsp; GBK 字
3.4.2 &nbsp; GBK 字
</span>
</a>
@@ -3585,7 +3583,7 @@
<li class="md-nav__item">
<a href="#343-unicode" class="md-nav__link">
<span class="md-ellipsis">
3.4.3 &nbsp; Unicode 字
3.4.3 &nbsp; Unicode 字
</span>
</a>
@@ -3646,23 +3644,23 @@
<!-- Page content -->
<h1 id="34">3.4 &nbsp; 字元編碼 *<a class="headerlink" href="#34" title="Permanent link">&para;</a></h1>
<p>在計算機中,所有資料都是以二進位制數的形式儲存的,字元 <code>char</code> 也不例外。為了表示字元,我們需要建立一套“字集”,規定每個字元和二進位制數之間的一一對應關係。有了字集之後,計算機就可以透過查表完成二進位制數到字元的轉換。</p>
<h2 id="341-ascii">3.4.1 &nbsp; ASCII 字<a class="headerlink" href="#341-ascii" title="Permanent link">&para;</a></h2>
<p><u>ASCII 碼</u>是最早出現的字集,其全稱為 American Standard Code for Information Interchange(美國標準資訊交換程式碼)。它使用 7 位二進位制數(一個位元組的低 7 位)表示一個字元,最多能夠表示 128 個不同的字元。如圖 3-6 所示,ASCII 碼包括英文字母的大小寫、數字 0 ~ 9、一些標點符號,以及一些控制字元(如換行符和製表符)。</p>
<p>在計算機中,所有資料都是以二進位制數的形式儲存的,字元 <code>char</code> 也不例外。為了表示字元,我們需要建立一套“字集”,規定每個字元和二進位制數之間的一一對應關係。有了字集之後,計算機就可以透過查表完成二進位制數到字元的轉換。</p>
<h2 id="341-ascii">3.4.1 &nbsp; ASCII 字<a class="headerlink" href="#341-ascii" title="Permanent link">&para;</a></h2>
<p><u>ASCII 碼</u>是最早出現的字集,其全稱為 American Standard Code for Information Interchange(美國標準資訊交換程式碼)。它使用 7 位二進位制數(一個位元組的低 7 位)表示一個字元,最多能夠表示 128 個不同的字元。如圖 3-6 所示,ASCII 碼包括英文字母的大小寫、數字 0 ~ 9、一些標點符號,以及一些控制字元(如換行符和製表符)。</p>
<p><a class="glightbox" href="../character_encoding.assets/ascii_table.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="ASCII 碼" class="animation-figure" src="../character_encoding.assets/ascii_table.png" /></a></p>
<p align="center"> 圖 3-6 &nbsp; ASCII 碼 </p>
<p>然而,<strong>ASCII 碼僅能夠表示英文</strong>。隨著計算機的全球化,誕生了一種能夠表示更多語言的 <u>EASCII</u>集。它在 ASCII 的 7 位基礎上擴展到 8 位,能夠表示 256 個不同的字元。</p>
<p>在世界範圍內,陸續出現了一批適用於不同地區的 EASCII 字集。這些字集的前 128 個字元統一為 ASCII 碼,後 128 個字元定義不同,以適應不同語言的需求。</p>
<h2 id="342-gbk">3.4.2 &nbsp; GBK 字<a class="headerlink" href="#342-gbk" title="Permanent link">&para;</a></h2>
<p>後來人們發現,<strong>EASCII 碼仍然無法滿足許多語言的字元數量要求</strong>。比如漢字有近十萬個,光日常使用的就有幾千個。中國國家標準總局於 1980 年釋出了 <u>GB2312</u>集,其收錄了 6763 個漢字,基本滿足了漢字的計算機處理需要。</p>
<p>然而,GB2312 無法處理部分罕見字和繁體字。<u>GBK</u>集是在 GB2312 的基礎上擴展得到的,它共收錄了 21886 個漢字。在 GBK 的編碼方案中,ASCII 字元使用一個位元組表示,漢字使用兩個位元組表示。</p>
<h2 id="343-unicode">3.4.3 &nbsp; Unicode 字<a class="headerlink" href="#343-unicode" title="Permanent link">&para;</a></h2>
<p>隨著計算機技術的蓬勃發展,字集與編碼標準百花齊放,而這帶來了許多問題。一方面,這些字集一般只定義了特定語言的字元,無法在多語言環境下正常工作。另一方面,同一種語言存在多種字集標準,如果兩臺計算機使用的是不同的編碼標準,則在資訊傳遞時就會出現亂碼。</p>
<p>那個時代的研究人員就在想:<strong>如果推出一個足夠完整的字集,將世界範圍內的所有語言和符號都收錄其中,不就可以解決跨語言環境和亂碼問題了嗎</strong>?在這種想法的驅動下,一個大而全的字集 Unicode 應運而生。</p>
<p><u>Unicode</u> 的中文名稱為“統一碼”,理論上能容納 100 多萬個字元。它致力於將全球範圍內的字元納入統一的字集之中,提供一種通用的字集來處理和顯示各種語言文字,減少因為編碼標準不同而產生的亂碼問題。</p>
<p>自 1991 年釋出以來,Unicode 不斷擴充新的語言與字元。截至 2022 年 9 月,Unicode 已經包含 149186 個字元,包括各種語言的字元、符號甚至表情符號等。在龐大的 Unicode 字集中,常用的字元佔用 2 位元組,有些生僻的字元佔用 3 位元組甚至 4 位元組。</p>
<p>Unicode 是一種通用字集,本質上是給每個字元分配一個編號(稱為“碼點”),<strong>但它並沒有規定在計算機中如何儲存這些字元碼點</strong>。我們不禁會問:當多種長度的 Unicode 碼點同時出現在一個文字中時,系統如何解析字元?例如給定一個長度為 2 位元組的編碼,系統如何確認它是一個 2 位元組的字元還是兩個 1 位元組的字元?</p>
<p>然而,<strong>ASCII 碼僅能夠表示英文</strong>。隨著計算機的全球化,誕生了一種能夠表示更多語言的 <u>EASCII</u>集。它在 ASCII 的 7 位基礎上擴展到 8 位,能夠表示 256 個不同的字元。</p>
<p>在世界範圍內,陸續出現了一批適用於不同地區的 EASCII 字集。這些字集的前 128 個字元統一為 ASCII 碼,後 128 個字元定義不同,以適應不同語言的需求。</p>
<h2 id="342-gbk">3.4.2 &nbsp; GBK 字<a class="headerlink" href="#342-gbk" title="Permanent link">&para;</a></h2>
<p>後來人們發現,<strong>EASCII 碼仍然無法滿足許多語言的字元數量要求</strong>。比如漢字有近十萬個,光日常使用的就有幾千個。中國國家標準總局於 1980 年釋出了 <u>GB2312</u>集,其收錄了 6763 個漢字,基本滿足了漢字的計算機處理需要。</p>
<p>然而,GB2312 無法處理部分罕見字和繁體字。<u>GBK</u>集是在 GB2312 的基礎上擴展得到的,它共收錄了 21886 個漢字。在 GBK 的編碼方案中,ASCII 字元使用一個位元組表示,漢字使用兩個位元組表示。</p>
<h2 id="343-unicode">3.4.3 &nbsp; Unicode 字<a class="headerlink" href="#343-unicode" title="Permanent link">&para;</a></h2>
<p>隨著計算機技術的蓬勃發展,字集與編碼標準百花齊放,而這帶來了許多問題。一方面,這些字集一般只定義了特定語言的字元,無法在多語言環境下正常工作。另一方面,同一種語言存在多種字集標準,如果兩臺計算機使用的是不同的編碼標準,則在資訊傳遞時就會出現亂碼。</p>
<p>那個時代的研究人員就在想:<strong>如果推出一個足夠完整的字集,將世界範圍內的所有語言和符號都收錄其中,不就可以解決跨語言環境和亂碼問題了嗎</strong>?在這種想法的驅動下,一個大而全的字集 Unicode 應運而生。</p>
<p><u>Unicode</u> 的中文名稱為“統一碼”,理論上能容納 100 多萬個字元。它致力於將全球範圍內的字元納入統一的字集之中,提供一種通用的字集來處理和顯示各種語言文字,減少因為編碼標準不同而產生的亂碼問題。</p>
<p>自 1991 年釋出以來,Unicode 不斷擴充新的語言與字元。截至 2022 年 9 月,Unicode 已經包含 149186 個字元,包括各種語言的字元、符號甚至表情符號等。在龐大的 Unicode 字集中,常用的字元佔用 2 位元組,有些生僻的字元佔用 3 位元組甚至 4 位元組。</p>
<p>Unicode 是一種通用字集,本質上是給每個字元分配一個編號(稱為“碼點”),<strong>但它並沒有規定在計算機中如何儲存這些字元碼點</strong>。我們不禁會問:當多種長度的 Unicode 碼點同時出現在一個文字中時,系統如何解析字元?例如給定一個長度為 2 位元組的編碼,系統如何確認它是一個 2 位元組的字元還是兩個 1 位元組的字元?</p>
<p>對於以上問題,<strong>一種直接的解決方案是將所有字元儲存為等長的編碼</strong>。如圖 3-7 所示,“Hello”中的每個字元佔用 1 位元組,“演算法”中的每個字元佔用 2 位元組。我們可以透過高位填 0 將“Hello 演算法”中的所有字元都編碼為 2 位元組長度。這樣系統就可以每隔 2 位元組解析一個字元,恢復這個短語的內容了。</p>
<p><a class="glightbox" href="../character_encoding.assets/unicode_hello_algo.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Unicode 編碼示例" class="animation-figure" src="../character_encoding.assets/unicode_hello_algo.png" /></a></p>
<p align="center"> 圖 3-7 &nbsp; Unicode 編碼示例 </p>
@@ -3672,7 +3670,7 @@
<p>目前,UTF-8 已成為國際上使用最廣泛的 Unicode 編碼方法。<strong>它是一種可變長度的編碼</strong>,使用 1 到 4 位元組來表示一個字元,根據字元的複雜性而變。ASCII 字元只需 1 位元組,拉丁字母和希臘字母需要 2 位元組,常用的中文字元需要 3 位元組,其他的一些生僻字元需要 4 位元組。</p>
<p>UTF-8 的編碼規則並不複雜,分為以下兩種情況。</p>
<ul>
<li>對於長度為 1 位元組的字元,將最高位設定為 <span class="arithmatex">\(0\)</span> ,其餘 7 位設定為 Unicode 碼點。值得注意的是,ASCII 字元在 Unicode 字集中佔據了前 128 個碼點。也就是說,<strong>UTF-8 編碼可以向下相容 ASCII 碼</strong>。這意味著我們可以使用 UTF-8 來解析年代久遠的 ASCII 碼文字。</li>
<li>對於長度為 1 位元組的字元,將最高位設定為 <span class="arithmatex">\(0\)</span> ,其餘 7 位設定為 Unicode 碼點。值得注意的是,ASCII 字元在 Unicode 字集中佔據了前 128 個碼點。也就是說,<strong>UTF-8 編碼可以向下相容 ASCII 碼</strong>。這意味著我們可以使用 UTF-8 來解析年代久遠的 ASCII 碼文字。</li>
<li>對於長度為 <span class="arithmatex">\(n\)</span> 位元組的字元(其中 <span class="arithmatex">\(n &gt; 1\)</span>),將首個位元組的高 <span class="arithmatex">\(n\)</span> 位都設定為 <span class="arithmatex">\(1\)</span> ,第 <span class="arithmatex">\(n + 1\)</span> 位設定為 <span class="arithmatex">\(0\)</span> ;從第二個位元組開始,將每個位元組的高 2 位都設定為 <span class="arithmatex">\(10\)</span> ;其餘所有位用於填充字元的 Unicode 碼點。</li>
</ul>
<p>圖 3-8 展示了“Hello演算法”對應的 UTF-8 編碼。觀察發現,由於最高 <span class="arithmatex">\(n\)</span> 位都設定為 <span class="arithmatex">\(1\)</span> ,因此系統可以透過讀取最高位 <span class="arithmatex">\(1\)</span> 的個數來解析出字元的長度為 <span class="arithmatex">\(n\)</span></p>
@@ -3959,5 +3957,7 @@ aria-label="頁脚"
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.2/es5/tex-mml-chtml.min.js"></script>
<script>document$.subscribe(() => {const lightbox = GLightbox({"touchNavigation": true, "loop": false, "zoomable": true, "draggable": false, "openEffect": "zoom", "closeEffect": "zoom", "slideEffect": "none"});})</script></body>
<script id="init-glightbox">const lightbox = GLightbox({"touchNavigation": true, "loop": false, "zoomable": true, "draggable": false, "openEffect": "zoom", "closeEffect": "zoom", "slideEffect": "none"});
document$.subscribe(() => { lightbox.reload() });
</script></body>
</html>