windows 亂碼之 gbk 與 cp936


windows 亂碼之 gbk 與 cp936

在使用 node 子進程執行 cmd 命令時, 獲取到的輸出是亂碼的.

const { execSync } = require('child_process')
const res = execSync(`echo nihao 你好`)
console.log(`resres`, String(res))

事發原因

這是由於控制台輸入的編碼與 node 程序中使用的編碼不一致導致的.

相關疑問

可能你要問: 那是不是都改為 utf8 就行了? 並不行. 這就是 windows 控制台沒有默認是 utf8 的原因, 並且 utf8 與 gbk 也不是兼容的.

如果理解不兼容?

假設你修改 windows 控制台為 cp65001(utf8) 之后, 如果輸出的文本編碼是 utf8 的, 那么可以正常顯示. 但是如果在控制台中運行了某個程序, 他輸入的文本是 gbk 的, 那依然會亂碼.

查看控制台使用的編碼:

chcp

你可能要問: widnows 默認 gbk , 是不是代表它除了編碼問題之外, 都顯示幾乎所有的文字? 並不行. 這就是為什么還有 utf8 utf-16 的原因… gbk 只是在制定這個規范的時候, 能顯示幾乎所有中國的常見漢字. 那些一百來划的字或者生僻字, 就可能不能顯示了.

所以我認為, 編碼問題並沒有完美的解決方案. 那么在中國的 windows 環境下就暫認為都是 gbk 吧, 在基於這個的前提下, 我們就可以進行轉換了.

解決方法

在 node 中可以使用 iconv-lite 來進行轉換.

const { execSync } = require('child_process')
const { decode } = require('iconv-lite')

const res = execSync(`echo nihao 你好`)
console.log(`resres`, decode(res, `gbk`) )

擴展知識

在 windows 上我們可以用 chcp 獲取編碼來判斷是不是要進行 gbk 轉換, 如果不是的話, 會轉換錯誤.

所以最好進行一下判斷, 例如:

// 判斷當前環境是不是 gbk 編碼
const isGBK = require(`child_process`).execSync(`chcp`, {encoding: `utf8`}).match(/936/)

當然, 也可以粗暴一點直接判斷是不是中文環境, 是則使用 gbk:

/** * 判斷當前系統是不是中文 * @returns */
function isZh(){
  return [
    // 代碼頁為 936
    () => require(`child_process`).execSync(`chcp`, {encoding: `utf8`}).match(/936/),
    // 注冊表安裝語言為 0804
    () => require(`child_process`).execSync(`reg query "HKEY_LOCAL_MACHINE\\SYSTEM\\ControlSet001\\Control\\Nls\\Language" /v InstallLanguage`, {encoding: `utf8`}).match(/0804/),
    // 查看版本時輸出雙字節字符
    () => require(`child_process`).execSync(`ver`, {encoding: `utf8`}).match(/[\u4e00-\u9fa5]/),
    // 控制台語言配置為 zh_CN
    () => process.env.LANG.match(`zh_CN`),
  ].some(item => {
    try {
      return item()
    } catch (error) {
      return false
    }
  })
}

注, 一般情況下在其他系統下例如 mac 上是沒有這個問題的, 應該不會亂碼, 不需要轉 GBK.

關於 cp936 與 gbk

cp936 是 gbk, 936 是因為 IBM 發明代碼頁時, gbk 在代碼頁的第 936 頁.

關鍵字:NLS,cp936,GBK

  • NLS(Native Language System)
  • cp - code page
  • GB - guo biao 國標
  • GBK - guo biao kuo 國標擴展 - cp936
  • ANSI - 表示默認

在“控制面板”-“區域和語言選項”-“高級”-“代碼頁轉換表”可以看出“936 (ANSI/OEM - 簡體中文 GBK)”

注, 某些文章說它們其實不一樣~

參考


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM