js编写中文转unicode 教程

复制代码
function toFullUnicode(str) {
    let result = '';
    for (let i = 0; i < str.length; i++) {
      const codePoint = str.codePointAt(i);
      const hex = codePoint.toString(16).toUpperCase();
      
      if (codePoint <= 0xFFFF) {
        // 基本多文种平面 (BMP)
        result += '\\u' + '0'.repeat(4 - hex.length) + hex;
      } else {
        // 辅助平面
        result += '\\u{' + hex + '}';
        i++; // 跳过代理对
      }
    }
    return result;
  }
  console.log(toFullUnicode('😀中文'));  // \u{1F600}\u4E2D\u6587
  console.log("\u{1F600}\u4E2D\u6587")

中文转 Unicode 原理详解

1. 字符编码基础概念

1.1 字符集与编码

  • 字符集 (Character Set): 字符的集合

  • 编码 (Encoding): 将字符映射到二进制数据的规则

  • Unicode: 统一的字符集,为所有字符分配唯一编号(码点)

1.2 核心原理

复制代码
中文字符 → Unicode码点 → 十六进制表示 → Unicode转义序列
"中"    → U+4E2D      → 0x4E2D       → "\u4E2D"

2. Unicode 标准解析

2.1 Unicode 码点结构

复制代码
Unicode 字符平面结构:
├── 基本多文种平面 (BMP, 0x0000-0xFFFF)
│   ├── ASCII (0x0000-0x007F)
│   ├── 拉丁字母扩展 (0x0080-0x00FF)
│   ├── 中文、日文、韩文 (CJK) (0x4E00-0x9FFF)
│   └── 其他语言
├── 辅助平面 (0x010000-0x10FFFF)
│   ├── 扩展汉字 (0x20000-0x2A6DF)
│   └── 表情符号 (0x1F600-0x1F64F)

2.2 中文字符的 Unicode 范围

复制代码
常用中文字符分布:
1. 基本汉字 (CJK Unified Ideographs): U+4E00 - U+9FFF
   - 包含 20,902 个汉字
   - 示例:中(U+4E2D)、文(U+6587)

2. 扩展A区: U+3400 - U+4DBF
   - 包含 6,582 个汉字

3. 扩展B区: U+20000 - U+2A6DF
   - 包含 42,711 个汉字

4. 扩展C-F区: 更多生僻字

3. JavaScript 中的实现原理

3.1 核心方法原理

复制代码
// 原理1: charCodeAt() 内部机制
function simulateCharCodeAt(str, index) {
  // 实际实现步骤:
  // 1. 获取字符的UTF-16编码单元
  // 2. 返回0-65535之间的整数
  // 3. 对于基本平面字符,直接返回码点
  // 4. 对于辅助平面,返回代理对的高位或低位
  
  const code = str.charCodeAt(index);
  // JavaScript 使用 UTF-16 编码
  // BMP 字符: 直接映射
  // 辅助平面字符: 使用代理对 (surrogate pair)
  return code;
}

3.2 UTF-16 代理对原理

复制代码
// 辅助平面字符的编码方式
function encodeSurrogatePair(codePoint) {
  // codePoint > 0xFFFF 的字符需要代理对
  
  // 1. 减去 0x10000,得到20位值
  const code = codePoint - 0x10000;
  
  // 2. 分割为高10位和低10位
  const high = (code >> 10) + 0xD800;  // 高代理项: 0xD800-0xDBFF
  const low = (code & 0x3FF) + 0xDC00; // 低代理项: 0xDC00-0xDFFF
  
  return [high, low];
}

// 解码代理对
function decodeSurrogatePair(high, low) {
  // 验证是否为有效代理对
  if (high < 0xD800 || high > 0xDBFF) return null;
  if (low < 0xDC00 || low > 0xDFFF) return null;
  
  // 计算原始码点
  return ((high - 0xD800) << 10) + (low - 0xDC00) + 0x10000;
}

4. 转换过程的底层原理

4.1 从字符到码点

复制代码
// 底层实现步骤
function charToCodePoint(ch) {
  // 步骤1: 获取UTF-16编码单元
  const first = ch.charCodeAt(0);
  
  // 步骤2: 检查是否为高代理项
  if (first >= 0xD800 && first <= 0xDBFF) {
    // 是代理对的高位
    const second = ch.charCodeAt(1);
    if (second >= 0xDC00 && second <= 0xDFFF) {
      // 是有效的代理对
      return decodeSurrogatePair(first, second);
    }
  }
  
  // 步骤3: 直接返回(BMP字符)
  return first;
}

4.2 码点到十六进制的转换

复制代码
function codePointToHex(codePoint, padding = 4) {
  // 码点转为十六进制
  let hex = codePoint.toString(16).toUpperCase();
  
  // 补零
  if (hex.length < padding) {
    hex = '0'.repeat(padding - hex.length) + hex;
  }
  
  return hex;
}

5. 不同格式的 Unicode 表示

5.1 各种格式的转换规则

复制代码
// Unicode 转义序列的生成原理
function generateUnicodeEscape(codePoint, format) {
  switch (format) {
    case 'js':
      // JavaScript 格式: \uXXXX 或 \u{XXXXXX}
      if (codePoint <= 0xFFFF) {
        return '\\u' + codePointToHex(codePoint, 4);
      } else {
        return '\\u{' + codePointToHex(codePoint) + '}';
      }
      
    case 'html':
      // HTML 实体格式: &#XXXXX;
      return '&#' + codePoint + ';';
      
    case 'css':
      // CSS 格式: \XXXXXX
      return '\\' + codePointToHex(codePoint);
      
    case 'url':
      // URL 编码: %XX%XX%XX
      if (codePoint <= 0xFF) {
        return '%' + codePointToHex(codePoint, 2);
      } else {
        // UTF-8 编码
        const bytes = codePointToUTF8(codePoint);
        return bytes.map(b => '%' + b.toString(16).toUpperCase()).join('');
      }
  }
}

5.2 UTF-8 编码原理

复制代码
// 码点到 UTF-8 的转换
function codePointToUTF8(codePoint) {
  const bytes = [];
  
  if (codePoint <= 0x7F) {
    // 1字节: 0xxxxxxx
    bytes.push(codePoint);
  } else if (codePoint <= 0x7FF) {
    // 2字节: 110xxxxx 10xxxxxx
    bytes.push(0xC0 | (codePoint >> 6));
    bytes.push(0x80 | (codePoint & 0x3F));
  } else if (codePoint <= 0xFFFF) {
    // 3字节: 1110xxxx 10xxxxxx 10xxxxxx
    bytes.push(0xE0 | (codePoint >> 12));
    bytes.push(0x80 | ((codePoint >> 6) & 0x3F));
    bytes.push(0x80 | (codePoint & 0x3F));
  } else if (codePoint <= 0x10FFFF) {
    // 4字节: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
    bytes.push(0xF0 | (codePoint >> 18));
    bytes.push(0x80 | ((codePoint >> 12) & 0x3F));
    bytes.push(0x80 | ((codePoint >> 6) & 0x3F));
    bytes.push(0x80 | (codePoint & 0x3F));
  }
  
  return bytes;
}

6. JavaScript 字符串内部表示

6.1 字符串的内存结构

复制代码
// JavaScript 字符串的底层存储
const str = "中文";
// 内存中实际存储的是UTF-16编码
// "中": UTF-16编码: 0x4E2D
// "文": UTF-16编码: 0x6587

// 获取二进制表示
function getStringBinary(str) {
  const result = [];
  for (let i = 0; i < str.length; i++) {
    const code = str.charCodeAt(i);
    result.push(`0x${code.toString(16).toUpperCase()}`);
  }
  return result;
}

console.log(getStringBinary("中文")); // ["0x4E2D", "0x6587"]

6.2 代理对的特殊处理

复制代码
// 处理包含表情符号的字符串
const emoji = "😀中文";
console.log(emoji.length); // 4(😀占2个代码单元)

// 正确获取码点的方法
function getCodePoints(str) {
  const codePoints = [];
  for (let i = 0; i < str.length; i++) {
    const code = str.charCodeAt(i);
    
    if (code >= 0xD800 && code <= 0xDBFF) {
      // 高代理项
      const next = str.charCodeAt(i + 1);
      if (next >= 0xDC00 && next <= 0xDFFF) {
        // 有效的代理对
        const codePoint = decodeSurrogatePair(code, next);
        codePoints.push(codePoint);
        i++; // 跳过低位
        continue;
      }
    }
    
    codePoints.push(code);
  }
  return codePoints;
}

console.log(getCodePoints("😀中文"));
// [128512, 20013, 25991]

7. 转换算法的优化原理

7.1 查找表优化

复制代码
// 使用查找表加速常用字符的转换
class UnicodeConverter {
  constructor() {
    // 预计算常用字符的Unicode转义序列
    this.cache = new Map();
    this.commonChinese = new Set();
    
    // 预加载常用汉字
    for (let i = 0x4E00; i <= 0x9FA5; i++) {
      this.commonChinese.add(String.fromCharCode(i));
    }
  }
  
  toUnicode(str) {
    let result = '';
    for (let i = 0; i < str.length; i++) {
      const char = str[i];
      
      // 检查缓存
      if (this.cache.has(char)) {
        result += this.cache.get(char);
        continue;
      }
      
      // 计算Unicode转义序列
      const code = char.codePointAt(0);
      let unicodeSeq;
      
      if (code <= 0xFFFF) {
        unicodeSeq = '\\u' + code.toString(16).toUpperCase().padStart(4, '0');
      } else {
        unicodeSeq = '\\u{' + code.toString(16).toUpperCase() + '}';
      }
      
      // 缓存结果
      this.cache.set(char, unicodeSeq);
      result += unicodeSeq;
    }
    return result;
  }
}

7.2 正则表达式优化原理

复制代码
// 正则表达式的优化版本
function optimizedToUnicode(str) {
  // 使用正则一次性匹配所有非ASCII字符
  return str.replace(/[^\x00-\x7F]/gu, (char) => {
    const code = char.codePointAt(0);
    
    // 快速判断是否需要代理对
    if (code <= 0xFFFF) {
      return '\\u' + code.toString(16).toUpperCase().padStart(4, '0');
    } else {
      return '\\u{' + code.toString(16).toUpperCase() + '}';
    }
  });
}

8. 与其他编码的关系

8.1 Unicode 与 GB2312/GBK

复制代码
// Unicode 与 GBK 的映射原理
const gbkToUnicode = {
  // 示例:中文字符映射
  "0xB0A1": 0x554A, // "啊"
  "0xB0A2": 0x963F, // "阿"
  // ... 实际是庞大的映射表
};

// 转换过程
function gbkToUnicodeChar(gbkCode) {
  const unicodeCode = gbkToUnicode[gbkCode];
  if (unicodeCode) {
    return String.fromCharCode(unicodeCode);
  }
  return '?';
}

8.2 字节顺序标记 (BOM)

复制代码
// BOM 对 Unicode 编码的影响
function detectEncodingWithBOM(buffer) {
  if (buffer.length >= 2) {
    const bom = buffer.readUInt16BE(0);
    
    switch (bom) {
      case 0xFEFF: // UTF-16 BE
        return { encoding: 'utf16-be', hasBOM: true };
      case 0xFFFE: // UTF-16 LE
        return { encoding: 'utf16-le', hasBOM: true };
    }
  }
  
  if (buffer.length >= 3) {
    if (buffer[0] === 0xEF && buffer[1] === 0xBB && buffer[2] === 0xBF) {
      return { encoding: 'utf8', hasBOM: true };
    }
  }
  
  return { encoding: 'unknown', hasBOM: false };
}

9. 实际应用原理

9.1 网络传输中的编码

复制代码
// HTTP 请求中的编码处理
function prepareRequestData(data) {
  // 原理:将中文字符转为百分比编码
  return encodeURIComponent(data)
    .replace(/%/g, '\\x')
    .replace(/!/g, '%21')
    .replace(/'/g, '%27')
    .replace(/\(/g, '%28')
    .replace(/\)/g, '%29')
    .replace(/\*/g, '%2A');
}

9.2 数据库存储

复制代码
// 数据库中的Unicode存储原理
function encodeForDatabase(text) {
  // 1. 检测是否包含4字节字符(辅助平面)
  const hasSupplementary = /[\uD800-\uDBFF][\uDC00-\uDFFF]/.test(text);
  
  if (hasSupplementary) {
    // 需要UTF8mb4编码
    return {
      encoding: 'utf8mb4',
      data: text
    };
  } else {
    // 可以使用UTF-8
    return {
      encoding: 'utf8',
      data: text
    };
  }
}

10. 性能考虑

10.1 时间复杂度分析

复制代码
// 不同算法的时间复杂度
class UnicodePerformance {
  // 方法1: 简单循环 - O(n)
  simpleConvert(str) {
    let result = '';
    for (let i = 0; i < str.length; i++) {
      const code = str.charCodeAt(i);
      result += '\\u' + code.toString(16).padStart(4, '0');
    }
    return result;
  }
  
  // 方法2: 正则替换 - O(n) 但常数更小
  regexConvert(str) {
    return str.replace(/./g, (char) => {
      return '\\u' + char.charCodeAt(0).toString(16).padStart(4, '0');
    });
  }
  
  // 方法3: 数组拼接 - 更高效
  arrayConvert(str) {
    const parts = [];
    for (let i = 0; i < str.length; i++) {
      parts.push('\\u' + str.charCodeAt(i).toString(16).padStart(4, '0'));
    }
    return parts.join('');
  }
}

关键原理总结:

  1. 编码层次:字符 → Unicode码点 → 二进制表示 → 转义序列

  2. 代理对机制:辅助平面字符通过2个UTF-16代码单元表示

  3. 格式差异:JavaScript、HTML、URL各有不同的转义格式

  4. 性能优化:缓存、正则、数组拼接等优化技术

  5. 兼容性:处理BOM、代理对、编码检测等问题

相关推荐
威联通网络存储19 小时前
告别掉帧与素材损毁:威联通 QuTS hero 如何重塑影视后期协同工作流
前端·网络·人工智能·python
anOnion19 小时前
构建无障碍组件之Tabs Pattern
前端·html·交互设计
Rsun0455119 小时前
Redis中实现访问量计数
数据库·redis·缓存
天空属于哈夫克319 小时前
自动化素材中枢:实现云端文件与外部群消息的异步同步方案
数据库·oracle
Navicat中国20 小时前
Navicat Premium Lite 正式登录鸿蒙应用市场
数据库·华为·harmonyos·navicat
Yvonne爱编码20 小时前
数据库---Day 1 数据库基础
数据库·mysql·oracle
Ricky_Theseus20 小时前
数据库关系代数 - 连接操作
linux·数据库·算法
2301_7938046920 小时前
定时任务专家:Python Schedule库使用指南
jvm·数据库·python
一招定胜负20 小时前
课堂教学质量综合评分系统
java·linux·前端
橙露20 小时前
JavaScript 异步编程:Promise、async/await 从原理到实战
开发语言·javascript·ecmascript