You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript文本字体转换异常:仅部分字体生效求助

字体转换功能部分字体乱码问题排查与修复

问题描述

我正在开发一个类似lingojam.com的字体转换网站,使用JavaScript+Svelte+HTML实现输入文本的字体转换功能,但目前只有2种字体转换正常,其余字体转换后输出乱码/损坏。

测试文本为Feliz, Navidad.,相关代码及实际输出如下:

代码实现

JavaScript逻辑

function changeFont(text) {
  let output = "";

  for (const font in fonts) {
    const alphabet = Object.keys(fonts[font])[0];
    const transformedText = text
      .split("\n")
      .map((line) =>
        line
          .split("")
          .map((char) =>
            alphabet.includes(char)
              ? fonts[font][alphabet][alphabet.indexOf(char)]
              : char
          )
          .join("")
      )
      .join("\n");

    output += transformedText + "\n\n";
  }

  return output;
}

let newText = "Feliz, Navidad.";
let orignalText = "Feliz, Navidad.";

function changeInputText() {
  newText = changeFont(orignalText);
  console.log(newText);
}

changeInputText();

字体映射定义(HTML内脚本)

<script>
let fonts = {
  1: {
    abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ:
      "ᴀʙᴄᴅᴇғɢʜɪᴊᴋʟᴍɴᴏᴘǫʀsᴛᴜᴠᴡxʏᴢᴀʙᴄᴅᴇғɢʜɪᴊᴋʟᴍɴᴏᴘǫʀsᴛᴜᴠᴡxʏᴢ",
  },
  2: {
    abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ:
      "ᵃᵇᶜᵈᵉᶠᵍʰᶦʲᵏˡᵐⁿᵒᵖᵠʳˢᵗᵘᵛʷˣʸᶻᵃᵇᶜᵈᵉᶠᵍʰᶦʲᵏˡᵐⁿᵒᵖᵠʳˢᵗᵘᵛʷˣʸᶻ",
  },
  3: {
    abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ:
      "𝕒𝕓𝕔𝕕𝕖𝕗𝕘𝕙𝕚𝕛𝕜𝕝𝕞𝕟𝕠𝕡𝕢𝕣𝕤𝕥𝕦𝕧𝕨𝕩𝕪𝕫𝔸𝔹ℂ𝔻𝔼𝔽𝔾ℍ𝕀𝕁𝕂𝕃𝕄ℕ𝕆ℙℚℝ𝕊𝕋𝕌𝕍𝕎𝕏𝕐ℤ",
  },
  4: {
    abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ:
      "𝐚𝐛𝐜𝐝𝐞𝐟𝐠𝐡𝐢𝐣𝐤𝐥𝐦𝐧𝐨𝐩𝐪𝐫𝐬𝐭𝐮𝐯𝐰𝐱𝐲𝐳𝐀𝐁𝐂𝐃𝐄𝐅𝐆𝐇𝐈𝐉𝐊𝐋𝐌𝐍𝐎𝐏𝐐𝐑𝐒𝐓𝐔𝐕𝐖𝐗𝐘𝐙",
  },
  5: {
    abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ:
      "𝙖𝙗𝙘𝙙𝙚𝙛𝙜𝙝𝙞𝙟𝙠𝙡𝙢𝙣𝙤𝙥𝙦𝙧𝙨𝙩𝙪𝙫𝙬𝙭𝙮𝙯𝘼𝘽𝘾𝘿𝙀𝙁𝙂𝙃𝙄𝙅𝙆𝙇𝙈𝙉𝙊𝙋𝙌𝙍𝙎𝙏𝙐𝙑𝙒𝙓𝙔𝙕",
  },
  6: {
    abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ:
      "𝓪𝓫𝓬𝓭𝓮𝓯𝓰𝓱𝓲𝓳𝓴𝓵𝓶𝓷𝓸𝓹𝓺𝓻𝓼𝓽𝓾𝓿𝔀𝔁𝔂𝔃𝓐𝓑𝓒𝓓𝓔𝓕𝓖𝓗𝓘𝓙𝓚𝓛𝓜𝓝𝓞𝓟𝓠𝓡𝓢𝓣𝓤𝓥𝓦𝓧𝓨𝓩",
  },
  7: {
    abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ:
      "𝒶𝒷𝒸𝒹𝑒𝒻𝑔𝒽𝒾𝒿𝓀𝓁𝓂𝓃𝑜𝓅𝓆𝓇𝓈𝓉𝓊𝓋𝓌𝓍𝓎𝓏𝒜𝐵𝒞𝒟𝐸𝐹𝒢𝐻𝐼𝒥𝒦𝐿𝑀𝒩𝒪𝒫𝒬𝑅𝒮𝒯𝒰𝒱𝒲𝒳𝒴𝒵",
  },
};
</script>

实际输出

ғᴇʟɪᴢ, ɴᴀᴠɪᴅᴀᴅ.
ᶠᵉˡᶦᶻ, ⁿᵃᵛᶦᵈᵃᵈ.
�𝕗𝕞, �𝕜𝕓𝓫.
�𝐟𝐦, �𝐤𝐛𝐛.
�𝙛𝙢, �𝙠𝙗𝙗.
�𝓯𝓶, �𝓴𝓫𝓫.
�𝒻𝓂, �𝓀𝒷𝒷.

问题原因

乱码的核心是你处理的部分字符属于UTF-16代理对字符,但JavaScript默认按16位编码单元而非完整Unicode码点处理字符串:

  • 字体3到7的映射字符属于Unicode补充平面(如数学字母符号),这些字符在JS中以两个16位编码单元的形式存储
  • 使用split("")、indexOf和下标访问时,会把代理对拆成两个独立单元,导致取到不完整的字符片段,最终显示为�
  • 前两种字体的字符都是基础平面的单编码单元字符,所以不会出现问题

修复方案

修改字符串处理逻辑,改为基于Unicode码点的操作,确保完整处理代理对字符:

修复后的JavaScript代码

function changeFont(text) {
  let output = "";

  for (const font in fonts) {
    const [sourceAlphabet, targetAlphabet] = Object.entries(fonts[font])[0];
    // 把字母表转成码点数组,自动处理代理对
    const sourceChars = [...sourceAlphabet];
    const targetChars = [...targetAlphabet];

    const transformedText = text
      .split("\n")
      .map((line) =>
        [...line] // 按完整字符拆分每行
          .map((char) => {
            const idx = sourceChars.indexOf(char);
            return idx !== -1 ? targetChars[idx] : char;
          })
          .join("")
      )
      .join("\n");

    output += transformedText + "\n\n";
  }

  return output;
}

修复说明

  1. 使用[...str]展开字符串,会自动按完整Unicode码点拆分字符,正确识别代理对
  2. 将源字母表和目标字母表都转为码点数组,保证indexOf和下标访问的是完整字符
  3. 遍历每行文本时同样用[...line]处理,确保每个字符都被完整读取和转换

内容的提问来源于stack exchange,提问作者Shahzaib Hassan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 23:02:03