Unity文字显示带竖线问题

Unity 文字显示带竖线问题,一个肉眼看不见的 U+200C,让位图字体渲染成竖线

一、问题现象

反馈:剧情对话里,出现了大量莫名其妙的竖线,穿插在正常文字之间,严重影响观感。

起初反馈视频画质模糊,且竖线集中出现在同一段对话里,一度怀疑是录屏或模拟器的显示问题。但随后在真机上也稳定复现,排除了设备因素。

跟进后确认:竖线直接出现在 NGUI 的 UILabel 渲染结果里,并非贴图或 UI 层叠导致。检查了相关代码逻辑,也没有任何"单独插入竖线"的代码------至此基本可以断定,问题出在文本数据本身(翻译文案)

打开翻译源文件,肉眼却看不到任何竖线。直到把光标移到对应文字处、左右移动,才发现那里藏着一个不易察觉的字符------它不占明显宽度,肉眼几乎不可见,但渲染时却变成了一条竖线。

二、排查定位

2.1 第一反应:加空白字符筛查

既然定位到"看不见的字符",第一反应是在逻辑里加一层筛查替换,把各种不可见/空白字符过滤掉。于是写了一个 IsWhiteSpace 判断,把常见的空白字符枚举了一遍:

csharp 复制代码
bool IsWhiteSpace(char c)
{
    // 普通空格、制表符、换行符等
    if (char.IsWhiteSpace(c))
        return true;

    // 其他不可见字符
    switch (c)
    {
        case '\u00A0': // 不换行空格 (No-Break Space)
        case '\u2000': // 半身空距 (En Quad)
        case '\u2001': // 全身空距 (Em Quad)
        case '\u2002': // 半身空距 (En Space)
        case '\u2003': // 全身空距 (Em Space)
        case '\u2004': // 三分之一全身空距 (Three-Per-Em Space)
        case '\u2005': // 四分之一全身空距 (Four-Per-Em Space)
        case '\u2006': // 六分之一全身空距 (Six-Per-Em Space)
        case '\u2007': // 数字空距 (Figure Space)
        case '\u2008': // 标点空距 (Punctuation Space)
        case '\u2009': // 窄空距 (Thin Space)
        case '\u200A': // 最窄空距 (Hair Space)
        case '\u200B': // 零宽空格 (Zero Width Space)
        case '\u202F': // 窄不换行空格 (Narrow No-Break Space)
        case '\u205F': // 中数学空距 (Medium Mathematical Space)
        case '\u3000': // 全角空格 (Ideographic Space)
        case '\uFEFF': // 零宽不换行空格 (Zero Width No-Break Space)
        case '\u0009': // 制表符
        case '\u000A': // 换行
        case '\u000D': // 回车
        case '\u001C': // 文件分隔符
        case '\u001D': // 组分隔符
        case '\u001E': // 记录分隔符
        case '\u001F': // 单元分隔符
            return true;
        default:
            return false;
    }
}

结果:问题字符串依然没有被筛查出来

2.2 关键一步:逐字符打印 code point

既然枚举没覆盖到,索性放弃"猜字符",直接把字符串每个字符单独打印出来,看它到底是什么:

csharp 复制代码
for (int i = 0; i < strValue.Length; i++)
{
    Debug.Log($"char={i} code=U+{(int)strValue[i]:X4}");
}

打印结果立刻现形------那个"看不见的字符"是 U+200C

三、根因:U+200C 是什么

U+200C 是 ZERO WIDTH NON-JOINER(零宽非连接符,简称 ZWNJ),一个 Unicode 格式控制字符:

属性
码点 U+200C
名称 ZERO WIDTH NON-JOINER(零宽非连接符)
Unicode 类别 Format(Cf),而非 White_Space(Zs)
用途 抑制连字/合字,常出现在阿拉伯文、波斯文等需要控制字符连接关系的场景

两个关键点解释了整件事:

  1. 为什么 char.IsWhiteSpace 抓不到它 :.NET 的 char.IsWhiteSpace 只认 Unicode 类别为 Zs(空格分隔符)及少数 \t \n \r 等,而 U+200C 的类别是 Format(Cf),因此 char.IsWhiteSpace('\u200C') 返回 false 。上面第一版 IsWhiteSpace 虽然手列了 20 来个空白字符,但漏掉了 U+200C(它压根不是空白,而是格式符),所以筛查失败。

  2. 为什么渲染成竖线 :U+200C 本是"零宽、不可见"的控制符。但 NGUI 的 UILabel 用的是位图字体(Bitmap Font) ,字体图集里只包含导出时收录的字形。当图集里没有 U+200C 对应的 glyph 时,NGUI 会把它当作"缺字"处理,渲染成替换字形------在视觉上就表现为一条竖线(或缺字方块)。

来源 :U+200C 这类字符多来自网页文档复制、在线翻译工具、富文本编辑器粘贴进翻译文案,从源头很难 100% 规避。

四、修复方案

通过日志打印发现,有几十条翻译都带了这个字符。既然源头无法百分百规避,决定两条腿走路

  1. 工具筛查导出:对翻译文件做一次性扫描,把含 U+200C 的条目定位出来人工修正;
  2. 运行时兼容兜底 :加载文本时直接 Replace 掉 U+200C,确保线上不再出现竖线。
csharp 复制代码
const char ZWNJ = '\u200C';

bool ContainsU200C(string str)
{
    if (string.IsNullOrEmpty(str))
        return false;

    return str.IndexOf(ZWNJ) >= 0;
}

// 定位:打印出问题字符的位置与前后文,便于定位是哪条翻译
for (int i = 0; i < strValue.Length; i++)
{
    if (strValue[i] == '\u200C')
    {
        Debug.LogError(
            $"发现 U+200C,index={i}, 前后=[{strValue[Mathf.Max(0, i - 1)]}|{strValue[i]}|{strValue[Mathf.Min(strValue.Length - 1, i + 1)]}]"
        );
        break;
    }
}

// 兜底:直接删除零宽非连接符
strValue = strValue.Replace("\u200C", "");

经过测试,竖线问题得以修复。

五、排查要点总结

  1. "看不见的字符"别靠猜 :枚举再全也可能漏,最快的办法是逐字符打印 code pointU+XXXX 十六进制),一眼定位。
  2. char.IsWhiteSpace 有盲区 :它只覆盖 Zs 空白类别,Format(Cf) 类的零宽控制符(如 U+200C)不在此列,需单独处理。
  3. 零宽/格式字符家族要一起防:除 U+200C(ZWNJ)外,常见的还有 U+200D(ZWJ 零宽连接符)、U+200B(ZWSP 零宽空格)、U+FEFF(BOM/零宽不换行空格)等,翻译/粘贴场景建议一并筛查。
  4. 位图字体缺字会变形:NGUI/UIGUI 位图字体对图集外的码点没有 glyph,会渲染成替换字形(竖线/方块);排查文字异常时优先怀疑文本数据里混入了控制符。
相关推荐
qq_589666053 小时前
C语言、C++与C#的区别详解
c语言·c++·c#
淡海水3 小时前
04-02-哈希-Dictionary-TKey-TValue-上-核心数据结构
数据结构·算法·c#·哈希算法·编译·字典·dictionary
longxiaozhang65 小时前
C#异常处理:程序出错了怎么办?
开发语言·数据库·c#
界面开发小八哥6 小时前
界面控件DevExpress WinForms中文帮助文档 - 入门指南
ai·c#·.net·devexpress·ui开发·winforms
清风与日月6 小时前
Yitter.IdGenerator:高性能分布式唯一ID生成器详解
分布式·c#·.net·.netcore
SmalBox6 小时前
【Vertex着色器】Unity实现-体积雪效果
unity3d·游戏开发·图形学
影寂ldy7 小时前
C# WinForm TCP-Socket
网络·tcp/ip·c#
czhc11400756638 小时前
2026-08-25 博客:现场排查的 8 个坑
c#
Z5998178418 小时前
c#软件开发学习笔记--WPF(控件、样式)
笔记·学习·c#