You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何转义不可打印字符?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);
}

关键改动说明

  1. 替换长度写入逻辑:将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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 03:45:02