GBK全称《汉字内码扩展规范》(GBK即“国标”、“扩展”汉语拼音的第一个字母,英文名称:Chinese Internal Code Specification),GBK 向下与 GB 2312 编码兼容,向上支持 ISO 10646.1国际标准,是前者向后者过渡过程中的一个承上启下的产物。ISO 10646 是国际标准化组织 ISO 公布的一个编码标准,即 Universal Multilpe-Octet Coded Character Set(简称UCS),大陆译为《通用多八位编码字符集》,台湾译为《广用多八位元编码字元集》,它与 Unicode 组织的 Unicode 编码完全兼容。
GBK编码,是在GB2312-80标准基础上的内码扩展规范,使用了双字节编码方案,其编码范围从8140至FEFE(剔除xx7F),共23940个码位,共收录了21003个汉字,完全兼容GB2312-80标准,支持国际标准ISO/IEC10646-1和国家标准GB13000-1中的全部中日韩汉字,并包含了BIG5编码中的所有汉字。GBK编码方案于1995年10月制定, 1995年12月正式发布。
能显示中文的嵌入式设备,一般都支持GB2312,GB2312有很多适合小设备的优点:1)7000多汉字,基本覆盖常用生活场景;2)2字节编码,节省存储空间;3)向上兼容GBK。嵌入式设备一般能力有限,无法进行字符集的转码工作。
本文关注在嵌入式设备场景,嵌入式设备通过WiFi或者Ethernet提供一个小型的http服务器,用户通过PC或者手机的浏览器访问,并进行一些与汉字相关的配置操作。因为涉及到修改名称等直接与汉字有关的内容,因此,需要用到GBK编码的转换,简单说,当设备提供网页上要显示的内容时,设备内的httpd服务器提供GBK编码的内容(JSON)给浏览器,浏览器前端页面需要将GBK编码内容提取、转码后渲染页面(Unicode);当用户在页面编辑好汉字后,还需要将Unicode转码为GBK,返回给设备进行存储。
思路:访问服务器接口后,得到的JSON串(GBK编码)用blob格式转出,然后用FileReader来读取,读取时采用GBK编码格式处理。
fetch(`${baseHost}/status`)
.then(res => {
return res.blob();
})
.then(data => {
let reader = new FileReader();
reader.onload = () => {
const text = reader.result;
// console.log("返回:", text);
statusData = JSON.parse(text);
updateUI(); // 用收到的json内容更新UI
setData(); // 用收到的json内容更新控件
};
reader.readAsText(data, "gbk");
})
.catch(e => {
console.log(e);
});
|
思路:用户修改页面内容后,变量生成的JSON串(Unicode编码)转码为GBK格式Uint8Array,然后将Uint8Array用blob格式转出,并直接以二进制内容通过POST方式发回http服务器。
其中Unicode转GBK采用的查表方式,没有使用任何现有的转码方式,降低了对浏览器的依赖。使用TextDecoder('gbk')方法生成GBK码表,具体原理可以参考:
// 转码方法
function stringToGbk(str) {
const ranges = [
[0xA1, 0xA9, 0xA1, 0xFE],
[0xB0, 0xF7, 0xA1, 0xFE],
[0x81, 0xA0, 0x40, 0xFE],
[0xAA, 0xFE, 0x40, 0xA0],
[0xA8, 0xA9, 0x40, 0xA0],
[0xAA, 0xAF, 0xA1, 0xFE],
[0xF8, 0xFE, 0xA1, 0xFE],
[0xA1, 0xA7, 0x40, 0xA0],
]
const codes = new Uint16Array(23940)
let i = 0
for (const [b1Begin, b1End, b2Begin, b2End] of ranges) {
for (let b2 = b2Begin; b2 <= b2End; b2++) {
if (b2 !== 0x7F) {
for (let b1 = b1Begin; b1 <= b1End; b1++) {
codes[i++] = b2 << 8 | b1
}
}
}
}
const cstr = new TextDecoder('gbk').decode(codes)
// 编码表
const table = new Uint16Array(65536)
for (let i = 0; i < cstr.length; i++) {
table[cstr.charCodeAt(i)] = codes[i]
}
const buf = new Uint8Array(str.length * 2)
let n = 0
for (let i = 0; i < str.length; i++) {
const code = str.charCodeAt(i)
if (code < 0x80) {
buf[n++] = code
} else {
const gbk = table[code]
buf[n++] = gbk & 0xFF
buf[n++] = gbk >> 8
}
}
u8buf = buf.subarray(0, n)
// console.log(u8buf);
return u8buf
}
// 发送给http服务器,注意不需要添加Content-Type
// 将对象生成json(unicode格式)
const input = JSON.stringify(statusData, null, 0)
// 转码为GBK格式Uint8Array
let u8buf = stringToGbk(input);
// console.log(u8buf)
// GBK格式Uint8Array转为blob文件对象
const blob = new Blob([u8buf], {type: 'application/octet-stream'});
// 发送POST请求
fetch(`${baseHost}/save`, {
method: "post",
body: blob
})
|
带着使命来到世上的你,给他人提供价值,才有价值