全角字符的判断依据是Unicode码点范围,主要包括:0x3000(全角空格)、0x3000–0x303F、0x3400–0x4DBF、0x4E00–0x9FFF、0xFF01–0xFF5E等区段,需先将UTF-8字符串正确解码为码点再比对。

全角字符的判断依据是什么
全角字符在 Unicode 中没有统一的“全角属性”,但实际开发中,我们通常按编码范围来识别:中文、日文、韩文等 CJK 字符,以及全角 ASCII(如 、,、。、A、a)都落在特定 Unicode 区段。C++ 标准库不提供 iswide() 或类似函数,必须手动检查码点。
- 全角 ASCII 字符(如全角字母、数字、标点)集中在
0xFF01–0xFF5E(对应 !–~),0x3000(全角空格)单独存在 - CJK 统一汉字基本区为
0x4E00–0x9FFF,扩展 A 区为0x3400–0x4DBF,扩展 B/C/D/E 区更宽,但日常校验通常只覆盖前两个主要区段 - 判断前必须确保字符串是 UTF-8 编码且已正确解码为 Unicode 码点;直接对 UTF-8 字节流逐字节比对会出错
用 std::wstring_convert + std::codecvt_utf8 处理 UTF-8 字符串(C++11/14)
这是兼容性较好、无需第三方依赖的做法,适用于已知输入为合法 UTF-8 的场景:
- 先将
std::string转为std::wstring,再遍历每个wchar_t(注意:Windows 下wchar_t是 UTF-16,Linux/macOS 通常是 UTF-32,此处以 UTF-32 行为为准) -
std::wstring_convert已在 C++17 中被弃用,但仍在主流编译器(GCC 7+、Clang、MSVC)中可用
#include <string>
#include <locale>
#include <codecvt>
<p>bool has_fullwidth(const std::string& s) {
std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
try {
std::wstring ws = conv.from_bytes(s);
for (wchar_t c : ws) {
if ((c >= 0x3000 && c <= 0x303F) || // 日文平假片/片假名/平假名扩展等
(c >= 0x3400 && c <= 0x4DBF) || // CJK 扩展 A
(c >= 0x4E00 && c <= 0x9FFF) || // CJK 基本汉字
(c >= 0xFF01 && c <= 0xFF5E) || // 全角 ASCII
c == 0x3000) { // 全角空格
return true;
}
}
} catch (const std::range_error&) {
return false; // 非法 UTF-8 字节序列
}
return false;
}</p>- 注意:若输入含非法 UTF-8 序列,
conv.from_bytes()抛std::range_error,需捕获 - GCC 从 8.1 开始默认禁用
std::codecvt,需加编译选项-lstdc++并接受弃用警告;Clang 更严格,建议仅用于遗留项目
用 utf8cpp 库做轻量级 UTF-8 迭代(推荐用于新项目)
直接操作 UTF-8 字节流、避免 wchar_t 语义歧义,更可靠:
- 使用
utf8::next()逐个提取码点,返回uint32_t,天然支持完整 Unicode 空间 - 头文件仅依赖,无链接开销,兼容 C++11+
#include <utf8.h>
#include <string>
<p>bool has_fullwidth(const std::string& s) {
std::string::const_iterator it = s.begin();
while (it != s.end()) {
uint32_t cp;
try {
it = utf8::next(it, s.end(), cp);
} catch (const utf8::exception&) {
return false; // 解码失败
}
if ((cp >= 0x3000 && cp <= 0x303F) ||
(cp >= 0x3400 && cp <= 0x4DBF) ||
(cp >= 0x4E00 && cp <= 0x9FFF) ||
(cp >= 0xFF01 && cp <= 0xFF5E) ||
cp == 0x3000) {
return true;
}
}
return false;
}</p>- 不要漏掉
0x3000(全角空格)和0x303F(波浪线~),它们常被忽略 - 若需支持更多全角标点(如 ①、⑴、─),可补充
0x2460–0x24FF、0x2500–0x257F等区段
为什么不能用 iswprint() 或 iswalpha() 判断全角
这些宽字符分类函数行为依赖 locale,不可靠:
立即学习“C++免费学习笔记(深入)”;
-
iswprint(L'A')在"C"locale 下返回false,在"zh_CN.UTF-8"下可能返回true,结果不确定 - 它们只回答“是否可打印”或“是否字母”,不区分半角/全角;全角 A(U+FF21)和半角 A(U+0041)在多数 locale 下都被认为是字母
- 没有标准函数能直接回答“这个码点是不是全角字符”,必须靠显式范围匹配
真正容易被忽略的是:UTF-8 字符串必须先解码为码点再判断,绝不能对原始字节做 > 0x7F 这类简单判断——那只会把所有多字节 UTF-8 首字节(如汉字首字节 0xE4)误判为“全角”,而把单字节的全角空格 0xE3 0x80 0x80 拆成三个错误字节分别比对。


















