簡體   English   中英

如何將字符串復制到另一個字符串,在第一個位置留下空白字符?

[英]How to Copy a string to another leaving a blank character in the first position?

procedure Split(S: String; List: TStringList; Separator: Char);
var
  P, C: PAnsiChar;
  S, Buff: String;
begin
  List.Clear;

  if S = '' then
    Exit;

  List.BeginUpdate;

  (* [Ajusting size  - Slow *)
  if S[1] = Separator then
    Insert('', S, 1);

  S := S + Separator;
  (* Adjusting size] *)

  //Get Pointer to data
  P := PChar(S);

  //initial position
  C := P;
  while P^ <> #0 do //check if reached the end of the string
  begin
    //when found a separator
    if P^ = Separator then
    begin
      if P = C then //check if the slot is empty
        Buff := ''
      else //when it is not empty, make an string buffer
        SetString(Buff, C, P-C);

      List.Add(Buff); //add the string into the list
      Inc(C, P-C+1); //moves the pointer C to the adress of the pointer P
    end;

    Inc(P); //go to next char in the string
  end;

  List.EndUpdate;
end;

這段代碼工作正常但是在內存中移動字符串3次:

在方法調用中(按副本)
在插入('',S,1)
在連接中:S:= S +分隔符;

我想在S參數中添加const關鍵字,創建一個內部字符串來或多或少地復制數據:

  if S[1] = Separator then
  begin
    SetLength(Str, Length(S)+2);
    //HERE!! how to copy the string  
    Str[1] := ' ';
  end
  else
  begin
    SetLength(Str, Length(S)+1);
    //HERE!! how to copy the string   
  end;

  //Add Separator in the last position
  Str[Length(Str)] := Separator;

從而:

如果S包含';'
它將創建一個包含2個項目的字符串列表('','')。
如果S包含'; A'
它將創建一個包含2個項目的字符串列表('','A')。
如果S包含'A; A'
它將創建一個包含2個項目的字符串列表('A','A')。
如果S包含'A;'
它將創建一個包含2個項目('A','')的字符串列表。

像這樣:

if S[1] = Separator then
begin
  SetLength(Str, Length(S)+2);
  Move(Pointer(S)^, Str[2], Length(S)*SizeOf(Char));
  S[1] := ' '; // surely you mean Str[1] := ' '
end
else
begin
  SetLength(Str, Length(S)+1);
  Move(Pointer(S)^, Str[1], Length(S)*SizeOf(Char));
end;

//Add Separator in the last position
Str[Length(Str)] := Separator;

重新設計這個以避免重復是很容易的。

var
  dest: PChar;

if S[1] = Separator then
begin
  SetLength(Str, Length(S)+2);
  dest := @Str[2];
  S[1] := ' '; // surely you mean Str[1] := ' '
end
else
begin
  SetLength(Str, Length(S)+1);
  dest := @Str[1];
end;
Move(Pointer(S)^, dest^, Length(S)*SizeOf(Char));

//Add Separator in the last position
Str[Length(Str)] := Separator;

等等。 我會留給你去修飾它。

以下例程是我為Delphi 7編寫的(更准確地說,改編自SetDelimitedTextExtractStrings )以處理缺少TStrings.StrictDelimiter屬性的例程。 給定正確的參數,它將返回您想要的結果。

{
SplitString will expand the delimited string S into its component parts and
store them in Strings.  The primary difference between this routine and
Classes.ExtractStrings and TStrings.DelimitedText is that it does not treat
spaces, tabs, and CR/LF as delimiters whether you like it or not.  If Quotes
is non-empty, then quoted strings will be handled correctly.

Leading and Trailing whitespace is significant if TrimStrings is False.

If you want to eliminate empty tokens, set SkipEmptyStrings to True.

If you want Strings to be cleared before parsing, set ClearStrings to True.

This procedure is especially useful for dealing with CSV files exported from
Excel, since Excel does not quote a string unless it contains a comma.
Using ExtractStrings or TStrings.CommaText will fail with such files.

In Delphi 2006+, TStrings has the StrictDelimiter property that renders this
routine largely useless.
}
procedure SplitString(const S: string; Separators, Quotes: TSysCharSet; const Strings: TStrings; ClearStrings, TrimStrings, SkipEmptyStrings: Boolean);
var
  Head, Tail: PChar;
  Item: string;
  StringExists: Boolean;

  {$IF NOT Declared(CharInSet)}
  function CharInSet(C: Char; const CharSet: TSysCharSet): Boolean;
  begin
    Result := C in CharSet;
  end;
  {$IFEND}

begin
  StringExists := False;
  Strings.BeginUpdate;
  try
    if ClearStrings then
      Strings.Clear;
    if S = '' then
      Exit;

    Tail := PChar(S);
    while Tail^ <> #0 do begin
      if CharInSet(Tail^, Quotes) then
        Item := AnsiExtractQuotedStr(Tail, Tail^)
      else begin
        // Mark beginning of token
        Head := Tail;
        // Look for end of token, delineated by end of string or separator
        while (Tail^ <> #0) and not CharInSet(Tail^, Separators) do
          Inc(Tail);
        SetString(Item, Head, Tail - Head);
        if TrimStrings then begin
          Item := Trim(Item);
          Head := PChar(Item);
          if CharInSet(Head^, Quotes) then
            Item := Trim(AnsiExtractQuotedStr(Head, Head^));
        end;
        if not (SkipEmptyStrings and (Item = '')) then
          Strings.Append(Item);
      end;
      // If the last character in a string is a separator, then we need to mark
      // that another string exists, otherwise the next Inc(Tail) call will
      // place Tail^ at #0, we'll exit the while loop, and never know that there
      // was an empty string there to add.
      // --AAF
      StringExists := Tail^ <> #0;
      // Skip Separator
      if StringExists then
        Inc(Tail);
    end;
    // This can only happen if the very last character is a separator
    if StringExists and not SkipEmptyStrings then
      Strings.Append('');
  finally
    Strings.EndUpdate;
  end;
end;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM