如何让ICU验证GB2312编码时遇65533提前停止并报错?
如何让ICU在遇到无效GB2312字节时停止转换并报错?
我想使用ICU验证字节流是否采用GB2312编码,编写了如下C++代码:
bool is_gb2312(char *data, size_t len) { UErrorCode status = U_ZERO_ERROR; UConverter* conv = ucnv_open("GB2312", &status); if (U_FAILURE(status)) { std::cerr << "ucnv_open failed" << std::endl; return false; } auto* output = new UChar[len * 2]; UChar* target = output; char const* source = data; ucnv_toUnicode(conv, &target, output + len * 2, &source, data + len, nullptr, true, &status); if (U_FAILURE(status)) { std::cerr << "ucnv_toUnicode failed" << std::endl; return false; } delete[] output; ucnv_close(conv); return true; }但发现即使存在无效字节(如0xA1 0xA0),ICU也不会报错,仅将其转换为65533替换字符。请问如何让ICU在遇到65533时提前停止并上报错误?
解决方案
ICU默认采用替换字符处理无效输入,要实现遇到无效字节时立即停止转换并报错,只需修改转换器的错误处理模式:
关键修改步骤
设置错误处理行为为
UCNV_STOP_ON_ERROR
在打开转换器成功后,调用ucnv_setErrorAction函数,指定遇到无效输入时停止转换并触发错误:ucnv_setErrorAction(conv, UCNV_STOP_ON_ERROR, UCNV_STOP_ON_ERROR, &status);该函数的两个
UCNV_STOP_ON_ERROR参数分别控制"从Unicode转换"和"到Unicode转换"的错误行为,这里我们只需要后者生效,但统一设置更稳妥。完整修改后的代码
bool is_gb2312(char *data, size_t len) { UErrorCode status = U_ZERO_ERROR; UConverter* conv = ucnv_open("GB2312", &status); if (U_FAILURE(status)) { std::cerr << "ucnv_open failed" << std::endl; return false; } // 配置错误处理:遇到无效字节立即停止并上报错误 ucnv_setErrorAction(conv, UCNV_STOP_ON_ERROR, UCNV_STOP_ON_ERROR, &status); if (U_FAILURE(status)) { std::cerr << "ucnv_setErrorAction failed" << std::endl; ucnv_close(conv); return false; } auto* output = new UChar[len * 2]; UChar* target = output; char const* source = data; ucnv_toUnicode(conv, &target, output + len * 2, &source, data + len, nullptr, true, &status); bool isValid = U_SUCCESS(status); if (U_FAILURE(status)) { std::cerr << "ucnv_toUnicode failed: " << u_errorName(status) << std::endl; } delete[] output; ucnv_close(conv); return isValid; }
说明
UCNV_STOP_ON_ERROR会让ICU在检测到无效输入字节时立刻终止转换,并将status设置为具体错误码(例如U_INVALID_CHAR_FOUND)。- 必须在调用
ucnv_toUnicode之前配置错误处理行为,否则不会生效。 - 使用
u_errorName(status)可以输出具体错误名称,便于调试定位问题。
内容的提问来源于stack exchange,提问作者chenzhongpu
相关产品推荐
相关产品推荐

