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; }
修复说明
- 使用
[...str]展开字符串,会自动按完整Unicode码点拆分字符,正确识别代理对 - 将源字母表和目标字母表都转为码点数组,保证
indexOf和下标访问的是完整字符 - 遍历每行文本时同样用
[...line]处理,确保每个字符都被完整读取和转换
内容的提问来源于stack exchange,提问作者Shahzaib Hassan
相关产品推荐
相关产品推荐

