我有個小需求是要檢查專案程式檔是否混雜 Unicode、BIG5 等非 UTF-8 編碼,類似任務過去用 C# 寫過,例如:BIG5 GB2312繁簡編碼快篩潛盾機-解決VS2015程式檔BIG5相容問題,為了方便在工作上應用,我想寫個 PowerShell 版,以上是本次的企劃。

由於只需識別 UTF-8、Unicode、BIG5 三種編碼,且輸出結果是作為檢核警示,後續會有人工確認,不需要花太多時間涵蓋各種語系,邏輯也不需要 100% 精準,算是一次簡單任務。我的構想是用 File.ReadAllBytes() 讀入檔案 byte[] 後分別用 Encoding.UTF8、Encoding.Unicode 的 GetString() 轉成字串,檢測其中是否出現轉碼失敗的 � 字元來推測。

BIG5 的部分比較麻煩,如 GB2312 簡體中文或 Shift JIS 日文等泛 ANSI 類編碼,用 Encoding.GetEncoding(950) 轉字串,大部分字元可以對映到有效的繁體字碼區,但非中文常用字,無法對映的無效字元會變成 ?。我慣用的解法是用「無效字元*3 + 次常用字) / 總字元數」計算 BadSmell 指數,猜測它不是 BIG5 的機率。

程式範例如下:

function IsBig5([byte[]]$data) {
    $symbol = 0
    $common = 0
    $rare = 0
    $unknow = 0
    $ascii = 0
    $isDblBytes = $false
    $dblByteHi = 0
    foreach ($b in $data) {
        if ($isDblBytes) {
            if (($b -ge 0x40 -and $b -le 0x7e) -or ($b -ge 0xa1 -and $b -le 0xfe)) {
                $c = $dblByteHi * 0x100 + $b
                if ($c -ge 0xa140 -and $c -le 0xa3bf) {
                    $symbol++
                }
                elseif ($c -ge 0xa440 -and $c -le 0xc67e) {
                    $common++
                }
                elseif ($c -ge 0xc940 -and $c -le 0xf9d5) {
                    $rare++
                }
                else {
                    $unknow++
                }
            }
            else {
                $unknow++
            }
            $isDblBytes = $false
        }
        elseif ($b -ge 0x80 -and $b -le 0xfe) {
            $isDblBytes = $true
            $dblByteHi = $b
        }
        elseif ($b -lt 0x80) {
            $ascii++
        }
    }
    $total = $ascii + $symbol + $common + $rare + $unknow
    $badSmell = [float]($rare + $unknow * 3) / $total
    return $badSmell -lt 0.1;
}
function RoughDetectEncoding {
    param(
        [Parameter(Mandatory = $true)][string]$fileName
    )
    $res = @{
        Encoding = 'unknown'
        Content = ''
    };
    $bytes = [System.IO.File]::ReadAllBytes($fileName)
    $res.Content = [BitConverter]::ToString($bytes)
    $big5Enc = [System.Text.Encoding]::GetEncoding(950)
    # 若不容許 BIG5 夾雜無效編碼字元,
    # 可改條件為 $big5Enc.GetBytes($big5Enc.GetString($bytes)).Length -eq $bytes.Length -and (IsBig5 $bytes)
    if (IsBig5 $bytes) {
        $res.Encoding = 'big5'
        $res.Content = $big5Test
        return $res
    }   
    $utf8Test = [System.Text.Encoding]::UTF8.GetString($bytes)
    if (!$utf8Test.Contains("�")) {
        $res.Encoding = 'utf-8'
        $res.Content = $utf8Test
        return $res
    }
    $unicodeTest = [System.Text.Encoding]::Unicode.GetString($bytes)
    if (!$unicodeTest.Contains("�")) {
        $res.Encoding = 'unicode'
        $res.Content = $unicodeTest
        return $res
    }
    return $res
}

@('utf8.txt', 'unicode.txt', 'big5.txt', 'gb2312.txt', 'jis.txt') | ForEach-Object {
    $fileName = $_
    $res = RoughDetectEncoding -fileName $fileName
    Write-Host "File: $fileName, Encoding: $($res.Encoding)" -ForegroundColor Cyan
    Write-Host "$($res.Content)" -ForegroundColor White
}

我弄了簡單測試,同一段文字分別用 UTF-8、Unicode、BIG5 儲存,再加上簡體中文跟日文:

測試成功:

This article provide a rough but simple to to detect the encoding of text file with PowerShell.


Comments

# by Switch

隨著時代的演進和技術的進步,當年的潛盾機也開始變成可以握在手上就能開天闢地的勇者之劍了XD

# by Tony

對於 BadSmell 的計算方式有點疑惑… 除非已知輸入的資料會包含亂碼,不然正常的 BIG5 或 GB2312 文字檔,用正確的編碼方式去解讀,無效字元數應該都是0;換句話說,無效字元數不為0,就代表猜錯編碼了 承上,假設有個檔案剛好用BIG5及GB解碼都沒有無效字元,那麼上文所提的 BadSmell 公式,就變成「兩種編碼下所解讀出的『次常用字』比例較低者為正解」,換句話說,其實也就是比「誰的『常用字』比例較高」的意思 雖然「解碼錯誤次數」跟「常用字比例高低」兩者都是數字(字數),但畢竟還是不同概念,摻在一起計算,感覺還是有點不太直覺,畢竟「解碼錯誤1次」並不能折抵「3個次常用字」…

# by Jeffrey

to Tony, 解碼錯誤 + 常用字比例高低 不是一種嚴謹的判斷準則,絕對可以找到誤判的實例。 「(無效字元*3 + 次常用字) / 總字元數」是我依據實測抓出來的數字,實際用在我的資料對象成效挺好,誤判率很低。它偏向經驗法則,沒什麼理論依據,可以想成機器學習模型中的參數吧,實測效果不錯但沒法解釋。

# by Tony

仔細查看 BIG5 跟 GB2312 的編碼規則,就很容易找到例子來反證 舉例: 以 BIG5 編碼的「吘吽呏呁吨吤」,其 byte[] 為 "CA7E CAA1 CAA2 CAA3 CAA4 CAA5 " 12 bytes,這六個字都是 BIG5 裡的次常用字 若以 GB2312 編碼來解讀,會變成 「?省盛剩胜圣」,原因是,CA 7E 不屬於 GB2312 範圍,而 CA A1~CA A5 都是 GB2312 的常用字 得到 BadSmell:BIG5 是 5 (五個次常用字),GB2312 是 3 (一個無效字元),所以判斷為 GB2312 編碼 這樣的編碼判斷是蠻詭異的 當一種編碼有無效字元,而另一種編碼沒有時,理論上應該優先考慮 0 無效字元的編碼方式 不會去考慮 "次常用字佔多少比例",畢竟「無效字元」跟「次常用字」在正常情況下,是兩個不同層次的問題,不該混為一談 如果兩種編碼 "都有無效字元" 或 "都沒有無效字元" 那或許這種 BadSmell 公式可以當成一種進一步 "猜測" 的依據 但不應該在所有的 case 上都直接採取這樣的策略,因為反例真的太好找了 因為「GB2312 的常用字」跟「BIG5 的次常用字」剛好有一段編碼是重疊的 而 BIG5 部分編碼,也剛好在 GB2312 下無效 (BIG5 字元的第二 byte 可以是 40~7E,而 GB2312 不行)

# by Jeffrey

to Tony, 因於這是一種不嚴謹的判斷規則,刻意組合可拼出無限多個反例,所幸,正常文字剛好符合反例被誤判的機率並不高,至少依我的實測經驗是如此。 這種解題思路是「用低成本獲得 95% 以上正確率」,若實際檢測對象只有極低機會出現誤判,且誤判造成的損害不大,這就是一個的好方法。若你的資料形態特殊,誤判率偏高,可以再自己調整找出適合的參數。 當然,投入更多時間研究一定可以找出更精準的判斷規則,並預期能產生一些學術價值,但對快速解決眼前的問題並無助益。

# by Tony

事實上,就算多加幾個 if,先判斷兩種編碼分別有沒有異常字元,再做進一步處理,也不會影響什麼成本 BadSmell 正確率多少實在看不出來,但會出錯的 case 隨便舉都一大堆 畢竟公式本身就是亂湊的結果 (一個無效字元如何折抵三個次常用字元?) 只要你研究一下編碼規則,可以輕鬆舉出類似「吘吽呏呁吨吤」的例子出來 我也不覺得有必要花很多時間來做 BIG5 GB2312 的檢測 但一個「一看就知道有問題」的檢測方法,可能也不是一個解決問題的好方法 就像「吘吽呏呁吨吤」這個例子 試過其它軟體,目前還沒有遇到把它會判斷成 GB2312 的 是 BIG5 跟 GB2312 的編碼原理太複雜了嗎? 還是這六個字很難判斷編碼嗎? 我想應該都不是吧

# by Tony

結論,如同前言所述: 「如果兩種編碼 "都有無效字元" 或 "都沒有無效字元" 那或許這種 BadSmell 公式可以當成一種進一步 "猜測" 的依據 但不應該在所有的 case 上都直接採取這樣的策略,因為反例真的太好找了」 這個 BadSmell 公式,可以當成一種「沒有辦法中的辦法」 在其它正規方法都沒辦法判斷簡繁時,使用 BadSmell 也不失為一種合理的手段 但在一開始,連兩種編碼下,異常字元的個數有多少,都不去分析、判斷、處理 就直接套 BadSmell 公式,誤判的機率就大幅提升了 要降低這種誤判機率,我想也不是什麼很困難複雜不可解的事吧

# by Jeffrey

to Tony, 關於為什麼不願意再花時間分析、研究找出更好更精準的方法,我有個好理由 - 這個「一看就知道有問題」的檢測方法已經成功滿足我的需求,我想不出繼續花優化它的動機。(電視故障敲一下變好,之後幾個月都正常,問題既然解決了應該很少人會堅持把電視拆開研究) 如此粗糙的方法套用在我的實際資料印象中沒遇到誤判,可推論我要掃瞄的文章、文字檔幾乎不會出現「吘吽呏呁吨吤」這種組合。若我的情境用 BadSmell 的誤判率已小於十萬分之一,不再研究降低誤判率跟其困難複雜度無關,而是生命要浪費在更美好的事物上。

# by Tony

BIG5 / GB2312 的判斷其實沒你想像那麼複雜,先上圖 https://i.imgur.com/YhoCa6k.png 1. 基本概念 BIG5 有 13,503 組不同 2-byte 組合,GB2312 有 7,445 組不同 2-byte 組合 兩者有共同的 7,101 組 2-byte 組合 2. BIG5 的場合 承上 一個任意 BIG5 字元轉換成 byte[] 後,可以解碼成另一個 GB2312 字元的機率是 (7101/13503) = 52.59% (上圖的BIG5第一行數據) 兩個任意 BIG5 字元轉換成 byte[] 後,可以解碼成另兩個 GB2312 字元的機率是 52.59% * 52.59% = 27.66%   (這裡有點取巧,實際值為 (7101/13503) * (7100/13502) = 27.65% 略小於 (52.59%)^2,圖片裡的數字都是實際值,非近似值) 八個任意 BIG5 字元……可以解碼成另八個 GB2312 字元的機率是 (52.59%)^8 = 0.58% (上圖的BIG5第三行數據) 由上圖可以得知,15 個任意 BIG5 字元轉換成 30 bytes 後,同時又可以「成功」解碼成 15 個 GB2312 字元的機率是 0.00646% 也就是說,15 個任意 BIG5 byte組合,解碼成 GB2312「不成功」的機率是 1 - 0.00646% = 99.99% (上圖的BIG5第五行數據) 當 BIG5 的字元數 (= byte 組合) 越多時,就幾乎不可能完美的解碼成 GB2312,其中必然會有無效字元 只需要少少 15 個字元 (= 30 bytes) 就能讓「正確判斷編碼是 BIG5 的機率」提升到超過 99.99%   (以上提到的「任意字元」,皆為「任意且不重複的字元」,同一字元不管重複多少次,都不會提升或減少正確率) 3. GB2312 的場合 一個任意 GB2312 字元轉換成 byte[] 後,可以解碼成另一個 BIG5 字元的機率是 (7101/7445) = 95.38% (上圖的GB2312第一行數據) 49個任意 GB2312 字元……可以解碼成另49個 BIG5 字元的機率是 (95.38%)^49 = 9.77% (上圖的GB2312第二行數據) … 193個任意 GB2312 字元……可以解碼成另193個 BIG5 字元的機率是 (95.38%)^193 = 0.0095% (上圖的GB2312第五行數據) 193個任意 GB2312 字元……無法解碼成另193個 BIG5 字元的機率是 1 - 0.0095% = 99.99% 由於 GB2312 有 95% 以上的 byte 組合,剛好也一樣是 BIG5 的 byte 組合 所以比起 BIG5,GB2312 被誤判的機率要高出許多,但在超過 193 字數 (386 bytes) 的情況下,誤判率也可以低到 0.01% 以下 4. 結論 a. 同一組 byte[] 資料,如果只在其中一種編碼下,有「無效字元」,那麼它就是另一種編碼 b. 如果在兩種編碼下「都沒有無效字元」:   由於 BIG5 的內容,只需要很少字元,在 GB2312 下出現無效字元的機率就很高   而 GB2312 的內容,則需要多很多字元,才能達到在 BIG5 下出現無效字元的相同機率   因此絕大多數的 case,都是 GB2312     => 可以直接判斷「在兩種編碼下都沒有『無效字元』」的 case 都是 GB2312 ,誤判率極低   舉例:任意 15 個 BIG5 字元轉 byte[] 後,全都不是 GB2312 下的無效字元的機率是 0.00646% (誤判率小於萬分之一) c. 如果在兩種編碼下「都有無效字元」   這邊就是一種類似 Exception (異常狀態) 的情形了   由於完全無法得知為何會發生這種非預期的意外,因此也沒有任何可以適用的準則   如果一定要套用 BadSmell 公式,大概就只適用於這種異常情況了 5. BadSmell 其實 BIG5 / GB2312 的判斷很簡單 完全不需要什麼「神來一筆」「無法解釋的神祕公式」 按照正常作法,分析 BIG5 跟 GB2312 之間 byte 組合的「重疊率」 在各個數字跟機率之間,就能找出合理的作法 回頭談談 BadSmell 公式 它最大的問題就在於「毫無合理性」   「一個『異常字元』,要怎麼抵銷對面的三個『次常用字元』?」 因此,它判斷 BIG5 / GB2312 的正確率,一定比正常作法低   (因為你永遠不知道,何時「次常用字元」會不合理的抵銷掉「異常字元」,造成程式的誤判) 就算判斷出正確的結果,你也無法解釋它怎麼辦到的,完全莫明其妙,只能感恩讚嘆 猜想你當初是因為「單純靠次常用字,無法準確判斷 BIG5/GB2312」的原因 所以才加上「無效字元 * 3」這個變數來解決問題 但其實只要靠「無效字元」本身就足以判斷 BIG5/GB2312 了 「無效字元*3」再加上「次常用字」的作法,只是畫蛇添足,而且反倒會增加出錯的機率 這就有點像「使用『3倍洗衣粉』再加上『爽身粉』來洗衣服」 雖然這樣也能把衣服洗得很乾淨 但這終究多半是「洗衣粉」的功勞 而加入「爽身粉」,到底是加分還是扣分,根本沒人知道 前面說「用低成本獲得 95% 以上正確率」 後面說「我的情境用 BadSmell 的誤判率已小於十萬分之一」 坦白說,這些數字完全沒有說服力 在你沒辦法判斷「BadSmell 公式何時能成立,何時不能成立」 也沒辦法說明「為什麼 BadSmell 就是特別有效」其原理的狀況下 是要怎麼計算出 95%,十萬分之一的數字來? 退一萬步來說 不管錯誤率是 5% 也好,十萬分之一也好 你有分析過 BadSmell 為什麼會出錯嗎? 我想應該也沒有吧 「生命應該浪費在美好的事物上」,我完全同意 分析「BIG5 跟 GB2312 的字元組成」,對我來說,就是一種值得浪費的事物 就像你也曾分析過 「在 decimal 下 24 ≠ 24.00」 的 case 在常人看來,可能也搞不懂,這東西有什麼好研究的 但對當事者來說,一定有某種意義存在,push 你去鑽研細節 不是嗎? 6. GBK 上圖中 GBK 的部分,只是順便用相同方式計算一下 BIG5 有 13,503 組不同 2-byte 組合,GBK 有 21,791 組不同 2-byte 組合 兩者有共同的 12,169 組 2-byte 組合 一個任意 BIG5 字元轉換成 byte[] 後,可以解碼成另一個 GBK 字元的機率是 (12169/13503) = 90.12% (上圖的BIG5/GBK第一行數據) 一個任意 GBK 字元轉換成 byte[] 後,可以解碼成另一個 BIG5 字元的機率是 (12169/21791) = 55.84% (上圖的GBK第一行數據) 其它分析就類似前面 BIG5 / GB2312 的 case,不贅述了

# by Tony

另外補充,前文提到的 BIG5 及 GBK,是以 CP950 及 CP936 所收錄的字元為標準 BIG5 跟 GBK 都還有其它標準,收錄的字元數也略有小差異

# by Jeffrey

to Tony, 感謝分享,佩服你的熱情與專業。依據你分析的結果,能否提出建議公式或演算法讓我補充在文章裡。

# by Tony

根據前面 post 的「4. 結論」,可以推導出以下公式: if ((無法被 GB2312 解碼的 byte 數 > 0) && (無法被 BIG5 解碼的 byte 數 > 0))   編碼 = Unknown; else if (無法被 GB2312 解碼的 byte 數 > 0)   編碼 = BIG5; else   編碼 = GB2312; 一般情況下,如果原始 byte[] 在 BIG5 & GB2312 解碼下都有「無法解碼的 byte」時 那麼很有可能,這組 byte[] 是 UTF-8 / UTF-16 LE / UTF-16 BE 或 S-JIS 或 任何其它編碼 如果很確定原始 byte[] 一定是 BIG5 或 GB2312 之一,沒有例外 只是因為某些原因導致 byte[] 裡內容出錯而無法解碼成功 那麼或許可以用 (無法被 BIG5 解碼的 byte 數) & (無法被 GB2312 解碼的 byte 數) 兩者之間誰比較小,來決定可能的編碼 也或許可以用 (經 BIG5 解碼後, 得到的常用字元數 / 得到的總字元數) & (經 GB2312 解碼後, 得到的常用字元數 / 得到的總字元數) 兩者之間誰比較大,來決定可能的編碼 但建議不要把兩種方法混合使用,因為這兩種猜測方式,都有它合理的理由 但混合之後就會產生無法解釋,也無法預知的結果

# by Tony

另外,為什麼 BadSmell 公式在你遇到的大部分情況下都適用,其原理大概是這樣: BadSmell = 「(無效字元*3 + 次常用字) / 總字元數」 由前面幾篇 POST,我們可以得知,判斷 BIG5/GB2312 的關鍵因素只有一個,就是「無效字元」數 次常用字 (或常用字) 的個數,或者是比例,都不會影響判斷結果 原因很簡單 當在 BIG5 (或 GB2312) 解碼後   1. 存在「無效字元」時,這個 byte[] 就不是這種編碼,不用再去考慮「次常用字」多寡   2. 當不存在「無效字元」時,這個 byte[] 就可能是這種編碼   3. 在兩種編碼下都不存在「無效字元」時,按照之前的 POST 所述,按照這個 byte[] 的長度,可以計算它可能是 BIG5 編碼的機率     2 bytes (1 字元) => 52.59%     8 bytes (4 字元) => 7.65%     16 bytes (8 字元) => 0.58%     30 bytes (15 字元) => 0.00646% (小於萬分之1)    在兩種編碼下都不存在「無效字元」時,它可能是 BIG5 編碼的機率極低,也不用考慮「次常用字」多寡 也就是說,「次常用字多寡」不能影響判斷結果,否則就會誤判 在你遇到的大部分情況下 BadSmell 公式主要是都是靠「無效字元」數來決定編碼 「次常用字」多寡無法發揮「決定性」的影響,所以判斷結果是正確的 但是,當「次常用字」的多寡,發揮「決定性」的影響時,判斷結果就會發生錯誤 (可說是反客為主) 就像那個例子「吘吽呏呁吨吤」一樣 當然這種情況發生的機率很低,可能不到 0.1%,0.01%,甚至更低,但並不會是 0

# by Tony

題外話 現在已經沒有純粹的 GB2312,它完全被 GBK 繼承了 很多地方可能顯示是 GB2312 編碼,但實際上是 GBK (像 EmEditor 讀檔時可以選擇編碼,而 GB2312 的選項,實際上是 GBK) 所以實務上要判斷編碼的話,應該需要判斷是 BIG5 或 GBK,不太需要判斷是否為純 GB2312 了

# by Tony

考慮到 BIG5, GBK (包含 GB2312 以外的字元), GBK (僅含純 GB2312 內的字元) 三種情況的話 判斷公式大概是這樣: if ((無法被 BIG5 解碼的 byte 數 > 0) && (無法被 GBK 解碼的 byte 數 > 0))   編碼 = Unknown; // (可被 BIG5 解碼) 或 (可被 GBK 解碼) else if (無法被 BIG5 解碼的 byte 數 > 0)   編碼 = GBK; // (可被 BIG5 解碼),需要判斷是否為「原 GB2312 字元所組成的偽 GBK」 else if (無法被 GB2312 解碼的 byte 數 > 0)   編碼 = BIG5; // 原 GB2312 字元所組成的偽 GBK else   編碼 = GBK;

# by Jeffrey

to Tony, 不確定我有沒有誤解你的意思。只用無效字元判斷的做法失誤率蠻高的(這是我加入次常用字來判斷的理由),我們可以很容易找到在 BIG5 跟 GB2312 都有效的文字組合: 例如:'用簡單測試來驗證',其 BIG5 二進位格式為 A5-CE-C2-B2-B3-E6-B4-FA-B8-D5-A8-D3-C5-E7-C3-D2 以上內容可用 GB2312 或 GBK 解碼為 'ノ虏虫代刚ㄓ喷靡',八個字都是有效字元。 依你的判斷公式,由於 BIG5, GB2312, GBK 無法解碼 byte 數均為零,這段 BIG5 資料會被歸為 GBK。

# by Tony

等待複核中,留言將在稍後顯示 / The comment is awaiting review.

# by Jeffrey

to Tony, 了解了,感謝分享。我想 Bad Smell 簡略解法的成功使用經驗,應該也是基於「在正常情況下,只要字元數 (byte 數) 夠多,誤判幾乎完全不可能發生」這個理由。

# by Tony

BadSmell 的致命錯誤在於: 「當一組 byte[] 其中有無法被解碼成 BIG5 的字元時 BadSmell 仍然可有能會猜它是 BIG5」 沒人能解釋為什麼這樣的字串「為何會被當作 BIG5」,只能說「根據 BadSmell 公式,所以.....它是 BIG5」 但原因就在於, BadSmell 公式根本連最基本的解碼錯誤,都有可能會忽略掉,所以根本沒意義 只有在「完全能解碼成 BIG5」 同時也「完全能解碼成 GB2312」時 程式才有需要做一步的「判斷」或說是「猜測」 如果有無法解碼的字元,我想也沒必要猜了吧

# by Tony

另外,我也計算了 BIG5 及 GB2312 共用的 7,101 byte 組合,分別解碼成 BIG5 跟 GB2312 後,再計算它們常用字/次常用字/其它字元的個數及比例 如果將其解碼成 BIG5,常用字 / 次常用字 / 其它 的字元個數及比例是 2490 (35.07%) / 4413 (62.15%) / 198 (2.79%) 如果解碼成 GB2312,常 / 次常 / 其它 的字元個數及比例是 3473 (48.91%) / 3008 (42.36%) / 620 (8.73%) 從上面數字可以發現,如果有一組 byte[] 同時可以解碼成 BIG5 或 GB2312 那麼可以從「BIG5 常用字 vs BIG5 次常用字 的比例」來判斷這組 byte[] 是 BIG5 或 GB2312 因為在正常分布下,「BIG5 常用字的比例」只比「BIG5 次常用字的比例」的一半多一點 所以,當「BIG5 常用字」的個數大於「BIG5 次常用字」時,理論上就很有機會是 BIG5 圖片在 imgur xfZTFa5 其它數字就不解釋了,有興趣的話可以自行研究

# by Jeffrey

to Tony, 當 byte[] 無法被解碼成 BIG5 字元跳過 BIG5 判斷,我的做法是 `if ((!$big5Test.Contains("?") -or $bytes -contains 0x3f) -and (IsBig5 $bytes)) )`,若原始內容沒有 ? 但解碼完出現 ?,代表有 byte[] 無法被解碼。這個做法的缺點是當原本就含 ? 時只能依據 Bad Smell,優點是程式寫法簡單,不用仔細核對編碼區間。 另外,關於常用字次常用字的比例估算,唯有字元採全隨機產生,在常態分配下才會出現「BIG5 常用字的比例」只比「BIG5 次常用字的比例」的一半多一點,若處理對象是日常真實的文字,常用字的數量應完全輾壓次常用字才對,至於比例多少?我也想知道,有空來玩看看。

# by Tony

只要把 byte[] 解碼後的 BIG5 字串,再一次編碼成 BIG5 的 byte[],比較兩者長度是否相同,就能知道是不是有無法解碼的字元 不需要糾結於 '?' 上面

# by Jeffrey

to Tony, 這招比較好,之前我在 C# 有用過竟忘了,謝謝提醒。

Post a comment