惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
The Blog of Author Tim Ferriss
I
InfoQ
H
Hackread – Cybersecurity News, Data Breaches, AI and More
aimingoo的专栏
aimingoo的专栏
小众软件
小众软件
有赞技术团队
有赞技术团队
J
Java Code Geeks
Apple Machine Learning Research
Apple Machine Learning Research
大猫的无限游戏
大猫的无限游戏
Engineering at Meta
Engineering at Meta
B
Blog RSS Feed
博客园_首页
Y
Y Combinator Blog
V
Visual Studio Blog
Google DeepMind News
Google DeepMind News
M
MIT News - Artificial intelligence
雷峰网
雷峰网
博客园 - 司徒正美
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
H
Help Net Security
P
Proofpoint News Feed
B
Blog
云风的 BLOG
云风的 BLOG
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报

博客园 - papering

由于系统缓冲区空间不足或队列已满,不能执行套接字上的操作 string byte 内存 硬盘 CAS ABA AtomicLong mysql 索引长度限制 docker network FTP Connection Modes (Active vs. Passive) 字符长度 mysql 【车载架构】AUTOSAR CP系列之27:系统内核之 WdgM 看门狗管理 单目录文件数限制 在联表 join 时 使用 case when 按不同的条件关联不同的行 JDK21 Process Reaper TLS 栈溢出循环故障深度分析 栈溢出 写入相邻的内存区域 GCC 的 -fstack-protector 会在每个函数的栈帧底部放一个随机“金丝雀值”,函数返回前检查它是否被改掉,以此检测栈缓冲区溢出。 潜伏5年!GitLab高危RCE漏洞爆发,低权限即可控服 Redis 漏洞分析——lua 脚本篇 Redis guarantees the script's atomic execution. AMQP 0-9-1 连接通过 信道 进行多路复用,信道可以被认为是“共享单一 TCP 连接的轻量级连接”。 WSAETIMEDOUT WSAEACCES This module supports asynchronous I/O on multiple file descriptors. 设置其优先级值的线程的句柄 QT 主线程 优化 卡顿 主线程上的同步重活 防重入:进行中直接 return,避免连点双开。 把「一次性任务」收到 ThreadPoolExecutor(max_workers=2~3),限制峰值线程数 统一 Activity 浮层 去掉连环成功弹窗 为 with语句上下文提供的工具 懒加载 IDE发现 import Canvas 指纹 魔改chromium源码——CDP(Chrome DevTools Protocol)检测01 whether the browser environment is controlled by a robot. chromium指纹魔改 对拷线 rpa 任务编排 a JSON formatted stream to ``fp`` 浏览器背后的黑科技 多进程 多线程 callback technique: signals and slots
“幽灵字符”问题
papering · 2026-06-27 · via 博客园 - papering

 某个位置的字符被替换成了视觉上相同、但底层编码不同的字符

全角(Full-width):每个字符占用两个标准字符位置,常用于中文标点、汉字以及部分英文字符和符号。全角字符在视觉上更宽,适合中文排版,保证文字对齐整齐。
半角(Half-width):每个字符占用一个标准字符位置,主要用于英文字符、数字和西文标点。半角字符在程序代码、英文文档或不支持中文的系统中使用较多。
既然长度相等且肉眼看起来一样,说明不是多了一个隐藏字符(否则长度会不同),而是某个位置的字符被替换成了视觉上相同、但底层编码不同的字符。
以下是导致这种现象最常见的 4 个原因及排查方法:
1. 全角与半角字符混淆(最常见)
肉眼看起来都是空格或字母,但一个是半角(ASCII),一个是全角(中文输入法下打出的)。
半角空格: ' ' (Unicode: U+0020)
全角空格: ' ' (Unicode: U+3000)
全角字母: A (Unicode: U+FF21) vs 半角 A (Unicode: U+0041)
2. 零宽字符(Zero-width characters)
这些字符在屏幕上不占宽度、不可见,但它们是真实的字符,会占用字符串长度。
零宽空格 (U+200B)
零宽非连接符 (U+200C)
零宽连接符 (U+200D)
场景:从网页、PDF、微信复制文本时,经常会自动插入这些字符用于排版或防复制。
3. Unicode 规范化问题(NFC vs NFD)
这在处理带声调的字母(如法语、西班牙语)或Emoji时极易发生。同一个视觉符号,底层有两种存储方式:
组合形式 (NFC): é 作为一个单独的字符 (U+00E9)
分解形式 (NFD): e (U+0065) + ́ (组合重音符号 U+0301)
结果:肉眼看都是 é,长度也都是 1(或对应比例),但 == 比较为 False。macOS 的文件系统默认使用 NFD,而 Linux/Windows 多用 NFC,跨平台传数据时极易踩坑。
4. 相似字形字符(Homoglyphs)
不同语言或不同区块中,长得一模一样的字符:
西里尔字母 а (U+0430) vs 拉丁字母 a (U+0061)
数字 0 (U+FF10) vs 数字 0 (U+0030)

零宽空格

Unicode名称说明
U+200B 零宽空格 (ZWSP) 最常见的零宽字符,用于指示可换行点,从网页/PDF复制文本时极易混入
U+200C 零宽非连接符 (ZWNJ) 阻止相邻字符连写,常见于阿拉伯语、波斯语排版
U+200D 零宽连接符 (ZWJ) 强制相邻字符连写,Emoji 组合(如 👨‍👩‍👧‍👦)就是靠它实现的
U+2060 单词连接符 (Word Joiner) 类似零宽空格,但禁止在该位置换行
U+FEFF 零宽无断空格 / BOM 标记 文件开头标识编码格式(UTF-8 BOM = EF BB BF),也可能出现在字符串首尾

文本方向控制

Unicode名称说明
U+200E 左至右标记 (LRM) 强制后续文本从左到右排列
U+200F 右至左标记 (RLM) 强制后续文本从右到左排列
U+202A 左至右嵌入 (LRE) 嵌套的从左到右方向控制
U+202B 右至左嵌入 (RLE) 嵌套的从右到左方向控制
U+202C 弹出方向格式 (PDF) 结束上述方向嵌套
U+202D 左至右覆盖 (LRO) 强制从左到右覆盖方向
U+202E 右至左覆盖 (RLO) 强制从右到左覆盖方向(常被用于文件名伪装攻击)

其他

Unicode名称说明
U+00AD 软连字符 (Soft Hyphen) 仅在断行时显示为连字符,平时不可见
U+034F 组合图形连接符 (CGJ) 不可见,用于影响组合字符的处理
U+061C 阿拉伯字母标记 (ALM) 影响阿拉伯语排版方向
U+180E 蒙古文元音分隔符 在蒙古文中不可见,但影响排版

清楚零宽字符

import re

def remove_zero_width(text):
    """移除所有零宽字符和不可见控制字符"""
    return re.sub(r'[\u200B-\u200F\u202A-\u202E\u2060\uFEFF\u00AD\u034F\u061C\u180E]', '', text)

# 使用示例
str1 = "hello"      # 看起来是 hello
str2 = "hello"      # 真正的 hello
print(str1 == str2)  # False!
print(remove_zero_width(str1) == str2)  # True