合法utf-8需按字节模式验证:单字节0xxxxxxx、双字节110xxxxx 10xxxxxx、三字节1110xxxx 10xxxxxx 10xxxxxx、四字节11110xxx 10xxxxxx 10xxxxxx 10xxxxxx;非法字节(如孤立10xxxxxx、11111xxx等)应跳过,推荐用状态机逐字节过滤。

如何判断一个字节序列是否为合法UTF-8
UTF-8不是逐字节可验证的,必须按字节模式组合识别:单字节0xxxxxxx、双字节110xxxxx 10xxxxxx、三字节1110xxxx 10xxxxxx 10xxxxxx、四字节11110xxx 10xxxxxx 10xxxxxx 10xxxxxx。任意位置出现10xxxxxx但前面没匹配到对应起始字节(如110xxxxx),或出现11111xxx/10xxxxxx开头的孤立字节,都算非法。
别用std::string::erase()边遍历边删——迭代器失效风险高;也别依赖std::codecvt_utf8(C++17已弃用且实现常有bug)。
用状态机逐字节扫描并过滤非法字节
写一个轻量状态机,输入字节流,输出合法UTF-8子序列。状态包括:start(等待新字符)、expect1(期待1个后续字节)、expect2(期待2个)、expect3(期待3个)。遇到非法字节直接跳过,不计入输出。
- 遇到
0xxxxxxx→ 输出该字节,状态回start - 遇到
110xxxxx→ 记录需再读1字节,状态变expect1 - 遇到
1110xxxx→ 状态变expect2 - 遇到
11110xxx→ 状态变expect3 - 遇到
10xxxxxx→ 仅当处于expect*状态时才接受并推进计数;否则丢弃 - 遇到
11111xxx、11110000~11110100之外的四字节首字节、超范围码点(如U+D800~U+DFFF)也应丢弃
示例核心逻辑:
std::string filter_utf8(const std::string& s) {
std::string out;
int expecting = 0; // 0: start, 1/2/3: need that many trailing bytes
for (unsigned char c : s) {
if (expecting == 0) {
if ((c & 0x80) == 0) { // 0xxxxxxx
out += c;
} else if ((c & 0xE0) == 0xC0) { // 110xxxxx
if (c >= 0xC2 && c = 0xE0 && c = 0xF0 && c
<h3>为什么不能只删<code>0xFF</code>或<code>0x00</code>这类“明显坏字节”</h3>
<p>单个字节<code>0xFF</code>或<code>0xC0</code>本身不违法UTF-8语法(<code>0xC0</code>是过长编码的起始,但仍是有效字节),真正问题在于上下文组合。比如<code>À </code>中<code>0xC0</code>后跟<code>0x20</code>(非<code>10xxxxxx</code>)才构成错误;而<code> </code>是合法的NBSP。盲目删除某个字节会破坏后续合法序列。</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill5502" title="C++ Code Review Master"><img
src="https://img.php.cn/upload/skill/000/000/081/179051228971575.jpg" alt="C++ Code Review Master" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill5502" title="C++ Code Review Master" class="overflowclass">C++ Code Review Master</a>
<p class="overflowclass">组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。</p>
</div>
<a rel="nofollow" href="/xiazai/skill5502" title="C++ Code Review Master" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>
<p>常见误操作:</p>
- 用
std::regex匹配"\x80-\xFF"然后删——这会干掉所有多字节字符的首字节 - 调用
iconv(..., "UTF-8", "ISO-8859-1", ...)再转回——可能静默替换或截断,不可控 - 依赖第三方库如
utf8cpp的is_valid()但只检查整体字符串——它返回false却不告诉你哪部分错,无法做局部清理
实际使用时要注意BOM和嵌入NUL
UTF-8 BOM()是合法字节序列,不应删除;但若原始字符串含C风格
