Uma*_*med 1 delphi firemonkey-fm2
我正在测试一些增强的字符串相关函数,我试图使用它作为一种复制字符串的方法,以便更快,更有效地使用而无需深入研究指针.
在测试用于从TStringList创建分隔字符串的函数时,我遇到了一个奇怪的问题.当编译器为空时,编译器引用了索引中包含的字节,并且当通过move添加字符串时,索引引用了包含的字符.
这是一个小型缩小的准系统代码示例: -
unit UI;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Rtti, System.Classes,
System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.Layouts,
FMX.Memo;
type
TForm1 = class(TForm)
Results: TMemo;
procedure FormCreate(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
function StringListToDelimitedString
( const AStringList: TStringList; const ADelimiter: String ): String;
var
Str : String;
Temp1 : NativeInt;
Temp2 : NativeInt;
DelimiterSize : Byte;
begin
Result := ' ';
Temp1 := 0;
DelimiterSize := Length ( ADelimiter ) * 2;
for Str in AStringList do
Temp1 := Temp1 + Length ( Str );
SetLength ( Result, Temp1 );
Temp1 := 1;
for Str in AStringList do
begin
Temp2 := Length ( Str ) * 2;
// Here Index references bytes in Result
Move ( Str [1], Result [Temp1], Temp2 );
// From here the index seems to address characters instead of bytes in Result
Temp1 := Temp1 + Temp2;
Move ( ADelimiter [1], Result [Temp1], DelimiterSize );
Temp1 := Temp1 + DelimiterSize;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
StrList : TStringList;
Str : String;
begin
// Test 1 : StringListToDelimitedString
StrList := TStringList.Create;
Str := '';
StrList.Add ( 'Hello1' );
StrList.Add ( 'Hello2' );
StrList.Add ( 'Hello3' );
StrList.Add ( 'Hello4' );
Str := StringListToDelimitedString ( StrList, ';' );
Results.Lines.Add ( Str );
StrList.Free;
end;
end.
Run Code Online (Sandbox Code Playgroud)
请设计一个解决方案,如果可能的话,还有一些解释.也欢迎替代品.
让我们看一下代码的关键部分:
// Here Index references bytes in Result
Move ( Str [1], Result [Temp1], Temp2 );
// From here the index seems to address characters instead of bytes in Result
Temp1 := Temp1 + Temp2;
Move ( ADelimiter [1], Result [Temp1], DelimiterSize );
Run Code Online (Sandbox Code Playgroud)
现在,一些解释.索引字符串时,始终为字符编制索引.你永远不会索引字节.它看起来好像你想索引字节.在这种情况下,使用字符串索引运算符会使生活变得困 所以我建议您按如下方式索引字节.
首先将Temp1初始化为0而不是1,因为我们将使用从零开始的索引.
当您需要Result使用从零开始的字节索引进行索引时,请执行以下操作:
PByte(Result)[Temp1]
Run Code Online (Sandbox Code Playgroud)
所以你的代码变成:
Temp1 := 0;
for Str in AStringList do
begin
Temp2 := Length(Str)*2;
Move(Str[1], PByte(Result)[Temp1], Temp2);
Temp1 := Temp1 + Temp2;
Move(ADelimiter[1], PByte(Result)[Temp1], DelimiterSize);
Temp1 := Temp1 + DelimiterSize;
end;
Run Code Online (Sandbox Code Playgroud)
事实上,我认为我会这样写,避免所有字符串索引:
Temp1 := 0;
for Str in AStringList do
begin
Temp2 := Length(Str)*2;
Move(Pointer(Str)^, PByte(Result)[Temp1], Temp2);
Temp1 := Temp1 + Temp2;
Move(Pointer(ADelimiter)^, PByte(Result)[Temp1], DelimiterSize);
Temp1 := Temp1 + DelimiterSize;
end;
Run Code Online (Sandbox Code Playgroud)
我会建议比Temp1和更好的名字Temp2.我也质疑NativeInt这里的用法.我通常希望看到Integer.尤其是因为Delphi string被带符号的32位值索引.您的string长度不能超过2GB.
另请注意,您没有分配足够的内存.你忘了考虑分隔符的长度.修复它,你的功能看起来像这样:
function StringListToDelimitedString(const AStringList: TStringList;
const ADelimiter: String): String;
var
Str: String;
Temp1: Integer;
Temp2: Integer;
DelimiterSize: Integer;
begin
Temp1 := 0;
DelimiterSize := Length(ADelimiter) * SizeOf(Char);
for Str in AStringList do
inc(Temp1, Length(Str) + DelimiterSize);
SetLength(Result, Temp1);
Temp1 := 0;
for Str in AStringList do
begin
Temp2 := Length(Str) * SizeOf(Char);
Move(Pointer(Str)^, PByte(Result)[Temp1], Temp2);
inc(Temp1, Temp2);
Move(Pointer(ADelimiter)^, PByte(Result)[Temp1], DelimiterSize);
inc(Temp1, DelimiterSize);
end;
end;
Run Code Online (Sandbox Code Playgroud)
如果你想避免指针,那么写这样:
function StringListToDelimitedString(const AStringList: TStringList;
const ADelimiter: String): String;
var
Str: String;
StrLen: Integer;
ResultLen: Integer;
DelimiterLen: Integer;
ResultIndex: Integer;
begin
DelimiterLen := Length(ADelimiter);
ResultLen := 0;
for Str in AStringList do
inc(ResultLen, Length(Str) + DelimiterLen);
SetLength(Result, ResultLen);
ResultIndex := 1;
for Str in AStringList do
begin
StrLen := Length(Str);
Move(Pointer(Str)^, Result[ResultIndex], StrLen*SizeOf(Char));
inc(ResultIndex, StrLen);
Move(Pointer(ADelimiter)^, Result[ResultIndex], DelimiterLen*SizeOf(Char));
inc(ResultIndex, DelimiterLen);
end;
end;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1526 次 |
| 最近记录: |