如何转义不可打印字符?Zig语言TLV编码问题求助
Zig语言TLV编码:将长度字段改为十进制字符串格式
问题描述
我用Zig编写了TLV编码代码,但运行后长度字段是不可打印的二进制字节(比如\x15对应数值21),而非预期的十进制字符串形式(比如长度3就写03)。
原代码
const std = @import("std"); fn getTLVForValue(writer: anytype, tagNum: []const u8, tagValue: []const u8) !void { _ = try writer.write(tagNum);; _ = try writer.writeByte(@intCast(tagValue.len)); _ = try writer.write(tagValue); } pub fn main() !void { var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); const allocator = arena.allocator(); var qrCodeBuf = std.ArrayList(u8).init(allocator); defer qrCodeBuf.deinit(); const writer = qrCodeBuf.writer(); //1. Seller Name try getTLVForValue(writer, "01", "Bobs Basement Records"); //2. VAT Registration try getTLVForValue(writer, "02", "312345678901233"); //3. Time stamp try getTLVForValue(writer, "03", "12-12-2023"); //4. tax Total try getTLVForValue(writer, "04", "1000"); //5. Vat Total try getTLVForValue(writer, "05", "115"); //6. Hashed XML try getTLVForValue(writer, "06", "dsds"); //7. key try getTLVForValue(writer, "07", "125"); //8. Signature try getTLVForValue(writer, "08", "dsfsd"); std.debug.print("{any}\n", .{qrCodeBuf.items}); std.debug.print("Hex string: {s}\n", .{std.fmt.fmtSliceHexUpper(qrCodeBuf.items)}); const output_buffer = try allocator.alloc(u8, std.base64.standard.Encoder.calcSize(qrCodeBuf.items.len)); defer allocator.free(output_buffer); const data = std.base64.standard.Encoder.encode(output_buffer, qrCodeBuf.items); std.debug.print("{s}\n", .{data}); const decode_buf = try allocator.alloc(u8, try std.base64.standard.Decoder.calcSizeForSlice(data)); try std.base64.standard.Decoder.decode(decode_buf, data); std.debug.print("{s}\n", .{decode_buf}); std.debug.print("{}\n", .{std.zig.fmtEscapes(decode_buf)}); try std.testing.expectEqualStrings(qrCodeBuf.items, decode_buf); }
当前问题输出
01\x15Bobs Basement Records02\x0f31234567890123303\n12-12-202304\x04100005\x0311506\x04dsds07\x0312508\x05dsfsd
需求
生成0103xxxx格式的TLV数据:标签(字符串)+ 十进制字符串形式的长度 + 值,比如长度为3时,长度字段写03而非二进制字节0x03。
解决方案
问题核心是原代码直接写入了长度的二进制字节值,我们需要改为写入长度的十进制字符串表示。只需修改getTLVForValue函数,用writer.print替代writeByte,将长度格式化为字符串写入即可。
修改后的代码
const std = @import("std"); fn getTLVForValue(writer: anytype, tagNum: []const u8, tagValue: []const u8) !void { _ = try writer.write(tagNum); // 将长度格式化为两位十进制字符串,不足补0;若需可变位数,改用{d}即可 try writer.print("{d:0>2}", .{tagValue.len}); _ = try writer.write(tagValue); } pub fn main() !void { var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); defer arena.deinit(); const allocator = arena.allocator(); var qrCodeBuf = std.ArrayList(u8).init(allocator); defer qrCodeBuf.deinit(); const writer = qrCodeBuf.writer(); //1. Seller Name try getTLVForValue(writer, "01", "Bobs Basement Records"); //2. VAT Registration try getTLVForValue(writer, "02", "312345678901233"); //3. Time stamp try getTLVForValue(writer, "03", "12-12-2023"); //4. tax Total try getTLVForValue(writer, "04", "1000"); //5. Vat Total try getTLVForValue(writer, "05", "115"); //6. Hashed XML try getTLVForValue(writer, "06", "dsds"); //7. key try getTLVForValue(writer, "07", "125"); //8. Signature try getTLVForValue(writer, "08", "dsfsd"); std.debug.print("{s}\n", .{qrCodeBuf.items}); std.debug.print("Hex string: {s}\n", .{std.fmt.fmtSliceHexUpper(qrCodeBuf.items)}); const output_buffer = try allocator.alloc(u8, std.base64.standard.Encoder.calcSize(qrCodeBuf.items.len)); defer allocator.free(output_buffer); const data = std.base64.standard.Encoder.encode(output_buffer, qrCodeBuf.items); std.debug.print("{s}\n", .{data}); const decode_buf = try allocator.alloc(u8, try std.base64.standard.Decoder.calcSizeForSlice(data)); defer allocator.free(decode_buf); try std.base64.standard.Decoder.decode(decode_buf, data); std.debug.print("{s}\n", .{decode_buf}); try std.testing.expectEqualStrings(qrCodeBuf.items, decode_buf); }
关键改动说明
- 替换长度写入逻辑:将
writeByte写入二进制字节的操作,改为用writer.print("{d:0>2}", .{tagValue.len})写入格式化后的十进制字符串。{d:0>2}表示将长度转为十进制整数,固定占两位,不足时左侧补0;如果你的场景允许长度为可变位数(比如长度100写100),可以直接用{d}作为格式化指令。
修改后输出示例
0121Bobs Basement Records0215312345678901233031012-12-20230404100005031150604dsds07031250805dsfsd
此时长度字段均为可读的十进制字符串,完全符合0103xxxx的格式要求。
内容的提问来源于stack exchange,提问作者Hasan A Yousef
相关产品推荐
相关产品推荐

