PHP读取库存扫描器日文全角字符字段截取异常求助
解决方案:按字节截取原始数据流,再转码处理
问题核心是混淆了字节长度和字符长度:库存扫描器输出的是固定128字节的二进制流,而日文全角字符在不同编码下字节数不同(比如SJIS中是2字节,UTF-8中是3字节)。如果先转码再用mb_substr按字符截取,会破坏原始固定字节边界,导致后续字段错位。
正确流程是:先按字节截取原始二进制数据,再将截取后的字节串转换为目标编码。
步骤1:确认扫描器的输出编码
日文设备(如库存扫描器)常用编码为SJIS(Shift-JIS),优先查看设备手册确认;若无法获取手册,可通过mb_detect_encoding初步检测(注意:检测结果可能有误差,需验证):
$rawRecord = fread($handle, 128); $detectedEncoding = mb_detect_encoding($rawRecord, ['SJIS', 'EUC-JP', 'UTF-8']);
步骤2:按字节截取字段(用substr而非mb_substr)
substr是PHP中按字节处理字符串的函数,完全匹配扫描器输出的固定字节结构。假设记录结构示例:
- 商品名称:前30字节
- 库存数量:接下来4字节
- 其他字段:剩余字节
示例代码:
// 读取完整128字节原始记录 $rawRecord = fread($handle, 128); // 按字节截取商品名称的原始字节串,再转码为UTF-8 $rawNameBytes = substr($rawRecord, 0, 30); $productName = mb_convert_encoding($rawNameBytes, 'UTF-8', 'SJIS'); // 按字节截取库存数量(ASCII编码数字),去除填充空格 $rawStockBytes = substr($rawRecord, 30, 4); $stockQuantity = trim($rawStockBytes); // 后续字段按相同逻辑处理 $rawOtherField = substr($rawRecord, 34, 94); $otherField = mb_convert_encoding($rawOtherField, 'UTF-8', 'SJIS');
关键注意事项
- 禁止先对整个128字节记录转码再截取:转码后字节数会变化(如SJIS转UTF-8时,全角字符从2字节变3字节),直接破坏原始固定字节结构。
- 若字段含全角空格,转码后可用
mb_trim处理(需指定编码):$productName = mb_trim($productName, 'UTF-8'); - 若检测编码与实际不符会出现乱码,此时必须优先确认设备官方编码说明。
内容的提问来源于stack exchange,提问作者K a r L
相关产品推荐
相关产品推荐

