一次「字符洁癖」引发的思考:我用 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」了。

相关推荐
ℋᙚᵐⁱᒻᵉ鲸落3 小时前
移动端滑动手势冲突:overflow: auto导致外层横向滑动失效
前端·javascript·css·vue.js·html
默_笙5 小时前
🎃 前端学了 Next.js,后端该学啥?NestJS 就是 Node 版的蜜雪冰城
前端·javascript
前端snow6 小时前
ai agent --- 实现 openclaw 定时间效果
前端
码云之上6 小时前
换模型之后,Chatbot 为什么要自己做 compact?
前端·agent·前端工程化
星栈6 小时前
自定义 UI-UX-Pro-Max 的 CSV 知识库,把 AI 生成的后台拉回行业该有的样子
前端·agent·weui
研☆香6 小时前
简单的图片上传 删除 预览
前端
ITresearchGuest7 小时前
我用 AI 一小时写了一个世界杯数据可视化平台|前端 VibeCoding 初体验
前端·人工智能·信息可视化
慧一居士8 小时前
Vite项目中使用Less步骤,详细使用示例
前端·css
花间相见8 小时前
【LangChain组件03】—— LangChain Agents 执行与状态:工作流程与状态管理实战
java·前端·langchain
kyriewen8 小时前
面试官让我用 AI 重构一个 8 年陈的 React 组件——他说他不看代码,只看我会不会拆
前端·javascript·面试