String Delphi中大字符串的安全连接

String Delphi中大字符串的安全连接,string,delphi,substring,concatenation,concat,String,Delphi,Substring,Concatenation,Concat,我在相当大的字符串上执行操作-我搜索给定短语的出现,并在我们称之为“数据库”(我准备了一个包含数据的文件,以便在R中进一步处理)上执行各种工作,正确使用两个过程/函数:Pos和StringReplace。它们中的大多数大小约为20-30MB,有时更大 从文档中,我知道所有声明为“字符串”的字符串,例如: my_string : String; 是“注意:在RAD Studio中,字符串是UnicodeString的别名”。这意味着我不必担心它们的大小或内存分配,因为RAD会自动完成。当然,在这

我在相当大的字符串上执行操作-我搜索给定短语的出现,并在我们称之为“数据库”(我准备了一个包含数据的文件,以便在R中进一步处理)上执行各种工作,正确使用两个过程/函数:Pos和StringReplace。它们中的大多数大小约为20-30MB,有时更大

从文档中,我知道所有声明为“字符串”的字符串,例如:

my_string : String;
是“注意:在RAD Studio中,字符串是UnicodeString的别名”。这意味着我不必担心它们的大小或内存分配,因为RAD会自动完成。当然,在这个阶段我可以问一个问题-您是否认为声明的选择对编译器很重要,并且会影响字符串的行为,因为它们在技术上是相同的

my_string1 : String;
my_string2 : AnsiString;
my_string3 : UnicodeString;
它对大小、分配、长度等有一定的意义(我们谈论的是超过20MB的丁字裤)

现在最重要的问题是-如何安全地将两个大字符串组合在一起?安全的内存泄漏和字符串内容,安全的程序速度等。这里有两个选项:

> var string1, string2: String;
> ...
> string1 := string1 + string2;
其中包含文档,并指出这是在Delphi中连接字符串的方法。但是还有另一种方法——我可以预先设置一个非常大的字符串大小,然后用move过程移动第二个内容

const string_size: Integer = 1024*1024;
var string1, string2: String;
    concat_place: Integer = 1;
...
SetLength(string1, string_size);
Move(string2[1],string1[concat_place],Length(string2));
Inc(concat_place,Length(string2));
这似乎更安全,因为内存中这个字符串的区域(大小)不会动态变化,我只是将适当的值移动到它。这是个更好的主意吗?还是说它们更好?也许我不明白什么

还有一个额外的问题——我使用Pos和AnsiPos测试了字符串和AnsiString搜索。它们似乎在所有组合中都起相同的作用。这是否意味着它们现在在Delphi中是相同的


提前感谢您提供的所有提示。

在Delphi中,字符串始终由编译器管理

在实践中,这意味着程序员根本不需要担心他们的内存分配或生存期,并且不会出现(意外的)内存泄漏。字符串与普通整数一样易于使用且安全(除非您开始做非常奇怪的事情)

在后台,字符串变量是指向字符串数据结构的指针,字符串是引用计数的,并使用写时复制语义。虽然您很可能不需要详细信息,但它们是

在Delphi 2009之前,字符串不是Unicode:它们每个字符使用一个字节,因此只有255个非空字符可用,由当前代码页确定。这是艰难的时期

在Delphi2009及更高版本中,字符串是Unicode字符串,每个字符有两个字节。因此,现在可以对字符串进行编码,如“∑γ + ∫sin²x dx“不费吹灰之力,而且您永远不需要担心代码页

您暗示您相信以下声明是相同的:

MyString1: string;
MyString2: AnsiString;
MyString3: UnicodeString;
在Delphi 2009中,
UnicodeString
string
是相同的:它们是Unicode字符串,每个字符有两个字节。但是,
AnsiString
是旧的(传统的,2009年以前)字符串类型,它每字符使用一个字节(最多255个非空字符),并且取决于代码页。尝试存储“∑γ + ∫sin²x dx“在一个
AnsiString

现在最重要的问题是如何安全地将两个大型 相互串连?对内存泄漏和字符串内容安全, 确保程序速度等

要在Delphi中组合两个字符串,几乎总是使用
+
运算符:
MyString1+MyString2
。这在正确性、内存管理等方面是100%安全的。不会有任何内存泄漏。在Delphi中连接字符串就是这么简单的

然而,就速度而言,在某些情况下,您可能能够在这方面有所改进。
+
运算符将使编译器创建代码,用于创建新的内部字符串数据结构,并将
MyString1
MyString2
的内容复制到该新区域

因此,例如,如果您想通过串联许多较小的字符串(甚至单个字符)来构建一个较大的字符串,您可以通过不使用连续的
+
操作,而是在开始时分配足够大的结果字符串(使用
SetLength
和字符计数)来获得(大量)性能以及手动将字符/字符串复制到其中(例如,使用
Move
和字节计数)

注意,我强调了byte这个词:你的例子

Move(string2[1], string1[concat_place], Length(string2));
很可能没有达到你的期望。由于字符串声明为
string
,因此在Delphi 2009及更高版本中,它们是Unicode字符串,因此每个字符有两个字节。因此,您需要复制
2*长度(string2)
字节。为了安全起见,我会写信的

Move(string2[1], string1[concat_place], sizeof(char) * Length(string2));
假设字符串声明为
string
,则此代码在2009年之前和2009年之后的Delphi版本中都可以使用。在Delphi 2009之前,
sizeof(char)
1
;在Delphi2009及更高版本中,
sizeof(char)
2

作为一个简单的基准,我尝试了

function GetChar: char;
begin
  Result := Char(1 + Random(1000));
end;

const
  N = 100000000;

function MakeString1: string;
var
  i: Integer;
begin
  Result := '';
  for i := 1 to N do
    Result := Result + GetChar;
end;

function MakeString2: string;
var
  i: Integer;
begin
  SetLength(Result, N);
  for i := 1 to N do
    Result[i] := GetChar;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  f, c1, c2: Int64;
  dur1, dur2: Double;
  s1, s2: string;
begin

  QueryPerformanceFrequency(f);

  QueryPerformanceCounter(c1);
  s1 := MakeString1;
  QueryPerformanceCounter(c2);
  dur1 := (c2 - c1) / f;

  QueryPerformanceCounter(c1);
  s2 := MakeString2;
  QueryPerformanceCounter(c2);
  dur2 := (c2 - c1) / f;

  ShowMessage(dur1.ToString + sLineBreak + dur2.ToString);

end;

在我的系统上,
MakeString1
在5秒内完成,
MakeString2
在1秒内完成。

谢谢,我想不出更好的解释:)但是,如果我理解正确,AnsiString只有一位字符大小,因此它可以用于AnsiString?>移动(string2[1],string1[concat_place],长度(string2));即使我在Delphi RAD Studio中编译它,AnsiString每个字符有一个字节(即8位,因此2^8=256个可能的字符)。所以一个字符=一个字节。因此,如果
string1
string2
确实属于
AnsiString
类型,那么您的代码片段就可以工作。