118 lines
3.4 KiB
JavaScript
118 lines
3.4 KiB
JavaScript
|
||
export function bytesToBase64(bytes) {
|
||
let binary = ''
|
||
for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i])
|
||
return btoa(binary)
|
||
}
|
||
|
||
export function base64ToBytes(str) {
|
||
const clean = str.replace(/\s/g, '')
|
||
const binary = atob(clean)
|
||
const bytes = new Uint8Array(binary.length)
|
||
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i)
|
||
return bytes
|
||
}
|
||
|
||
export function encodeBase64(text) {
|
||
return btoa(unescape(encodeURIComponent(text)))
|
||
}
|
||
|
||
export function decodeBase64(text) {
|
||
return decodeURIComponent(escape(atob(text)))
|
||
}
|
||
|
||
export function encodeUrl(text) {
|
||
return encodeURIComponent(text)
|
||
}
|
||
|
||
export function decodeUrl(text) {
|
||
return decodeURIComponent(text)
|
||
}
|
||
|
||
export function encodeUnicode(text) {
|
||
let result = ''
|
||
let i = 0
|
||
|
||
while (i < text.length) {
|
||
const codePoint = text.codePointAt(i)
|
||
|
||
if (codePoint > 0xFFFF) {
|
||
// 超出 BMP 的字符,使用代理对表示
|
||
const high = Math.floor((codePoint - 0x10000) / 0x400) + 0xD800
|
||
const low = ((codePoint - 0x10000) % 0x400) + 0xDC00
|
||
result += '\\u' + high.toString(16).toUpperCase().padStart(4, '0')
|
||
result += '\\u' + low.toString(16).toUpperCase().padStart(4, '0')
|
||
i += 2 // 代理对占用两个字符位置
|
||
} else {
|
||
// BMP 字符
|
||
result += '\\u' + codePoint.toString(16).toUpperCase().padStart(4, '0')
|
||
i++
|
||
}
|
||
}
|
||
|
||
return result
|
||
}
|
||
|
||
export function decodeUnicode(text) {
|
||
try {
|
||
let result = ''
|
||
let i = 0
|
||
|
||
while (i < text.length) {
|
||
// 匹配 \uXXXX 格式
|
||
if (text[i] === '\\' && i + 1 < text.length && text[i + 1] === 'u' && i + 5 < text.length) {
|
||
const hex = text.substring(i + 2, i + 6)
|
||
if (/^[0-9a-fA-F]{4}$/.test(hex)) {
|
||
const code1 = parseInt(hex, 16)
|
||
|
||
// 检查是否是高代理(surrogate high)
|
||
if (code1 >= 0xD800 && code1 <= 0xDBFF && i + 11 < text.length) {
|
||
// 检查下一个是否是低代理
|
||
if (text[i + 6] === '\\' && text[i + 7] === 'u') {
|
||
const hex2 = text.substring(i + 8, i + 12)
|
||
if (/^[0-9a-fA-F]{4}$/.test(hex2)) {
|
||
const code2 = parseInt(hex2, 16)
|
||
// 检查是否是低代理(surrogate low)
|
||
if (code2 >= 0xDC00 && code2 <= 0xDFFF) {
|
||
// 组合代理对
|
||
const codePoint = 0x10000 + ((code1 - 0xD800) << 10) + (code2 - 0xDC00)
|
||
result += String.fromCodePoint(codePoint)
|
||
i += 12
|
||
continue
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 普通字符或单独的代理
|
||
result += String.fromCharCode(code1)
|
||
i += 6
|
||
continue
|
||
}
|
||
}
|
||
|
||
// 匹配 \UXXXXXXXX 格式(8位十六进制)
|
||
if (text[i] === '\\' && i + 1 < text.length && text[i + 1] === 'U' && i + 9 < text.length) {
|
||
const hex = text.substring(i + 2, i + 10)
|
||
if (/^[0-9a-fA-F]{8}$/.test(hex)) {
|
||
const code = parseInt(hex, 16)
|
||
if (code > 0x10FFFF) {
|
||
throw new Error('无效的 Unicode 码点:超出范围')
|
||
}
|
||
result += String.fromCodePoint(code)
|
||
i += 10
|
||
continue
|
||
}
|
||
}
|
||
|
||
// 普通字符
|
||
result += text[i]
|
||
i++
|
||
}
|
||
|
||
return result
|
||
} catch (e) {
|
||
throw new Error('Unicode 解码失败:' + e.message)
|
||
}
|
||
}
|