gpt4 book ai didi

delphi - 字符串移动的奇怪行为

转载 作者:行者123 更新时间:2023-12-03 19:00:15 26 4
gpt4 key购买 nike

我正在测试一些与字符串相关的增强功能,试图将move用作复制字符串的一种方法,以便更快,更有效地使用字符串而无需深入研究指针。

在测试用于从TStringList生成分隔字符串的函数时,我遇到了一个奇怪的问题。当索引为空,并且通过移动将字符串添加到索引时,编译器引用索引中包含的字节,索引引用包含的字符。

这是一个小型的准系统代码示例:

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.


请设计解决方案,并在可能的情况下提供一些解释。也欢迎其他选择。

最佳答案

让我们看一下代码的关键部分:

// 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初始化为0而不是1,因为我们将使用基于零的索引。

当您需要使用从零开始的字节索引来索引 Result时,请执行以下操作:

PByte(Result)[Temp1]


因此,您的代码变为:

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;


实际上,我想我应该这样写,避免所有字符串索引:

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;


我建议使用比 Temp1Temp2更好的名称。我也在这里质疑 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;


如果要避免使用指针,请这样编写:

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;

关于delphi - 字符串移动的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19807858/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com