一次「字符洁癖」引发的思考:我用 AI 写了个全角半角转换工具

最近在整理项目文档时,遇到一个让我血压飙升的问题------从微信、PDF 或网页复制过来的文本,总是夹杂着各种「不三不四」的字符。明明看起来是正常的英文和数字,但粘贴到代码里就报错,搜索也搜不到。

排查了半天,罪魁祸首居然是全角字符 。全角的 ABC 和半角的 ABC 看起来几乎一样,但在程序眼里完全是两个不同的东西。这种「视觉混淆」在开发中造成的坑,相信不少朋友都踩过。

痛点:全角字符的「隐形炸弹」

在中文技术社区混久了,你会发现全角/半角问题是个「经典老番」。无论是:

  • 从微信聊天记录复制代码片段
  • 从 PDF 文档提取文本
  • 从 Word 粘贴到终端或编辑器
  • 处理用户提交的表单数据

全角字符总能以各种姿势给你「惊喜」。最典型的场景是------用户从某个中文输入法切到英文模式时,标点符号还是全角的。于是 if (x > 5) 变成了 if(x>5),直接编译报错。

传统解决方案无非是:手动逐个替换(效率低到让人崩溃)、写个简单的正则替换(但边界情况多如牛毛)、或者用一些重量级工具(杀鸡用牛刀)。

为什么不用现成的库?

说实话,市面上确实有不少现成的转换库,比如 fullwidth-halfwidthwcwidth 之类的。但在我的场景里,有几个考量:

  1. 体积问题:为了一个转换功能引入整个库,对轻量级工具来说有点「奢侈」
  2. 依赖管理:独立开发的小工具,能少一个依赖就少一个
  3. 可控性:自己实现,遇到特殊字符可以随时调整映射规则

于是,我决定用 AI 辅助开发一个纯前端、零依赖的转换工具。

和 AI 协作:从「能用」到「好用」

第一轮:给 AI 提需求

我用的方式是先给 AI 一个清晰的 prompt,描述需求和约束:

markdown 复制代码
写一个纯 JavaScript 的全角半角转换函数,要求:
1. 全角转半角
2. 半角转全角
3. 处理全角空格 U+3000
4. 处理全角标点 U+FF01-U+FF5E
5. 特殊货币符号映射
6. 不要修改原字符串
7. 处理 null/undefined 输入

AI 第一次生成的代码其实已经能跑,核心逻辑就是 charCodeAt 判断 + 偏移量加减。但有几个问题:

javascript 复制代码
// AI 第一版的问题代码
function toHalfWidth(str) {
  if (!str) return str;  // 问题:null 和 '' 都返回 null
  return str.replace(/[\uFF01-\uFF5E\u3000]/g, function(char) {
    return String.fromCharCode(char.charCodeAt(0) - 0xFEE0);
  });
}

这里有个典型的「AI 陷阱」:if (!str) 会把空字符串和 null 混淆,而且用正则替换的方式虽然简洁,但对特殊字符(如全角货币符号)的处理不够灵活。

第二轮:调优边界情况

我告诉 AI 这几个问题后,它迭代出了第二版,改用逐字符遍历的方式,并且把特殊映射表单独抽出来:

javascript 复制代码
var FWSpecial = {
  0xFFE0: '¢', 0xFFE1: '£', 0xFFE2: '¬',
  0xFFE3: '¯', 0xFFE4: '¦', 0xFFE5: '¥', 0xFFE6: '₩'
};

function toHalfWidth(str) {
  if (str == null) return '';
  var out = '';
  for (var i = 0; i < str.length; i++) {
    var c = str.charCodeAt(i);
    if (c === 0x3000) {
      out += ' ';
    } else if (c >= 0xFF01 && c <= 0xFF5E) {
      out += String.fromCharCode(c - 0xFEE0);
    } else if (FWSpecial[c]) {
      out += FWSpecial[c];
    } else {
      out += str.charAt(i);
    }
  }
  return out;
}

这一版明显靠谱多了,但 AI 的「过度设计」倾向也暴露了------它加了很多不必要的类型检查,比如 typeof str !== 'string' 之类的防御代码。对于这个场景,str == null 的判断已经足够了。

第三轮:处理「看不见」的坑

真正的坑在测试阶段才暴露出来。我拿了一段从微信复制的文本测试,发现全角空格 U+3000 被正确转换了,但全角逗号 全角句号 却原样保留。

原因是:微信复制出来的文本中,全角标点其实是 Unicode 中的「CJK 标点符号」区块(U+3001-U+303F),而不是全角 ASCII 区块(U+FF01-U+FF5E)。这俩完全是两回事。

我查了一下资料,发现这是个「历史遗留问题」------Unicode 在设计时把「全角 ASCII 变体」和「CJK 专用标点」分开了。于是跟 AI 讨论后,决定保持现状:只处理 U+FF01-U+FF5E 和 U+3000,CJK 标点保留原样。

这也是个很重要的设计决策:不要过度转换 。如果把 转成 ,,反而可能破坏中文排版的美感。

技术实现细节

最终的核心逻辑其实很简单,就是一个映射表 + 遍历:

javascript 复制代码
function toHalfWidth(str) {
  if (str == null) return '';
  var out = '';
  for (var i = 0; i < str.length; i++) {
    var c = str.charCodeAt(i);
    if (c === 0x3000) {
      out += ' ';  // 全角空格
    } else if (c >= 0xFF01 && c <= 0xFF5E) {
      out += String.fromCharCode(c - 0xFEE0);  // 全角 ASCII 变体
    } else if (FWSpecial[c]) {
      out += FWSpecial[c];  // 特殊货币符号
    } else {
      out += str.charAt(i);  // 其他字符原样保留
    }
  }
  return out;
}

反向转换 toFullWidth 就是反过来,把 0x21-0x7E 加上 0xFEE0 偏移。

这里有个有意思的点:为什么偏移量是 0xFEE0?因为 0xFF01 - 0x21 = 0xFEE0。全角字符和半角字符在 Unicode 里就差这个偏移量。

和 AI 协作的心得

这次开发让我对 AI 辅助编程有了新的认识:

  1. AI 擅长「骨架」,不擅长「边界」:它能快速生成核心逻辑,但边界情况(null、特殊字符、浏览器兼容性)往往需要人工补充
  2. prompt 要具体:给 AI 的描述越清晰,生成的代码质量越高。比如明确写出「处理 U+3000 全角空格」比「处理全角字符」效果好得多
  3. 测试驱动对话:拿真实场景的文本去测试 AI 生成的代码,把失败案例反馈给它,迭代速度会很快
  4. AI 会「过度设计」:有时候它会加一些不必要的防御代码,或者过度封装。这时候需要自己判断哪些是必要的

适用场景

这个工具最适合的场景:

  • 数据处理:清洗从各种渠道复制来的文本
  • 代码修复:处理用户输入中的全角字符
  • 文本规范化:统一文档中的字符格式
  • SEO 优化:避免因全角字符导致的搜索匹配问题

一点小思考

全角/半角问题看似简单,但背后涉及 Unicode 编码、字符映射、中文排版等多个领域的知识。这也是为什么我决定自己实现而不是直接用库------在解决「简单」问题的过程中,能学到不少「不简单」的细节

而且,纯前端实现还有个好处:数据完全在本地处理,不会上传到服务器。对于处理敏感文本的场景,这算是个「隐形加分项」。

如果你也经常被全角字符困扰,可以在线体验这个工具:craftvo.app/zh/tool/ful...

最后说一句:在 AI 辅助编程的时代,「会用 AI」和「懂原理」并不矛盾。恰恰是那些你理解原理的地方,才能判断 AI 生成的代码是否靠谱。这波操作,属于是「AI 教我的,但我也教了 AI」了。

相关推荐
想要成为糕糕手1 小时前
🚀 在浏览器里跑 DeepSeek-R1?WebGPU 端侧推理实战(五)—— 中断、重置、缓存与流式生成
前端·react.js·llm
GuWenyue1 小时前
后端接口又双叒没写好?3 步搭建前端 Mock,从此告别"傻等后端"
前端·mocha
海兰1 小时前
【数据采集】开源的 Web 数据采集与处理Firecrawl(一)
前端·开源
vivo互联网技术1 小时前
从一键检测到 AI 修复:我们如何把无障碍检查做进研发流程
前端·人工智能
liuxiaocheng1 小时前
聊聊 Vercel AI SDK 的流式协议:前后端到底是怎么"边想边说"的
前端·后端
胡萝卜术1 小时前
在浏览器中跑 DeepSeek-R1:WebGPU 推理全流程深度解析
前端·javascript·面试
windliang2 小时前
Claude Code 源码分析(十):MCP 外部工具如何进入下一轮 Agent 调用
前端·算法·面试
Yan_chen6662 小时前
CTFHub XSS反射型实战攻略
前端·网络安全·漏洞·xss·ctfhub web前置技能
web像素之境2 小时前
前端工程化梳理
前端