如何正确转换UTF-8缓冲区与Delphi普通字符串?解决尾零问题
Delphi无管理UTF-8缓冲区转换后出现尾随零的解决方法
问题描述
我按照Delphi官方建议编写了代码片段,无编译警告或隐式转换,但结果不符合预期。代码如下:
procedure Convert; type TUTF8Buf = array [0 .. 5] of byte; var s: string; sutf8: UTF8String; // 可管理的UTF-8字符串 utf8str: TUTF8Buf; // 无管理缓冲区 begin utf8str := Default (TUTF8Buf); // utf8str = (0,0,0,0,0,0) s := UTF8ArrayToString(utf8str); // s = #0#0#0#0#0#0 s := 'abc'; // s = 'abc' sutf8 := UTF8Encode(s); // sutf8 = 'abc' Move(sutf8[1], utf8str[0], Min(Length(sutf8), sizeof(utf8str) - 1)); // utf8str = (97, 98, 99, 0, 0) s := UTF8ArrayToString(utf8str); // s = 'abc'#0#0#0 s := UTF8ToString(sutf8); // s = 'abc' end;
使用可管理UTF-8字符串时运行正常,但使用无管理缓冲区时总会产生尾随零。请问处理此类缓冲区的现代正确方法是什么?
核心原因
UTF8ArrayToString会处理数组的全部字节,包括缓冲区中未被覆盖的尾随零。无管理缓冲区不像UTF8String那样自带长度标识,转换时必须明确指定有效数据的范围,而非让函数处理整个数组。
现代处理方法
方法一:使用带长度参数的UTF8ToString重载
从Delphi 10.3开始,System.SysUtils提供了接受字节指针和有效长度的UTF8ToString重载,直接转换缓冲区的有效部分:
procedure Convert; type TUTF8Buf = array [0 .. 5] of byte; var s: string; sutf8: UTF8String; utf8str: TUTF8Buf; validLen: Integer; begin s := 'abc'; sutf8 := UTF8Encode(s); validLen := Min(Length(sutf8), SizeOf(utf8str)); Move(sutf8[1], utf8str[0], validLen); // 传入缓冲区指针和有效长度进行转换 s := UTF8ToString(@utf8str[0], validLen); // 结果为'abc',无尾随零 end;
方法二:构造临时UTF8String(兼容旧版本)
如果你的Delphi版本不支持上述重载,可将缓冲区有效数据复制到临时UTF8String后再转换:
procedure Convert; type TUTF8Buf = array [0 .. 5] of byte; var s: string; sutf8: UTF8String; utf8str: TUTF8Buf; tempUTF8: UTF8String; validLen: Integer; begin s := 'abc'; sutf8 := UTF8Encode(s); validLen := Min(Length(sutf8), SizeOf(utf8str)); Move(sutf8[1], utf8str[0], validLen); // 构造仅包含有效数据的UTF8String SetLength(tempUTF8, validLen); if validLen > 0 then Move(utf8str[0], tempUTF8[1], validLen); s := UTF8ToString(tempUTF8); // 结果为'abc',无尾随零 end;
关键注意事项
- 不要依赖零作为终止符:UTF-8编码允许包含零字节(如编码U+0000),用零判断结束会导致错误,必须始终跟踪有效数据长度。
- 缓冲区大小计算:无需刻意预留终止符位置,直接使用实际有效长度即可,带长度的转换函数不需要依赖终止符。
内容的提问来源于stack exchange,提问作者Molochnik
相关产品推荐
相关产品推荐

