Szukaj…


Typy ciągów

Delphi ma następujące typy ciągów (w kolejności popularności):

Rodzaj Maksymalna długość Minimalny rozmiar Opis
string 2 GB 16 bajtów Zarządzany ciąg. Alias dla AnsiString za pośrednictwem Delphi 2007 oraz alias dla UnicodeString od Delphi 2009.
UnicodeString 2 GB 16 bajtów Ciąg zarządzany w formacie UTF-16.
AnsiString 2 GB 16 bajtów Ciąg zarządzany w formacie ANSI sprzed Unicode. Począwszy od Delphi 2009, zawiera wyraźny wskaźnik strony kodowej.
UTF8String 2 GB 16 bajtów Ciąg zarządzany w formacie UTF-8, zaimplementowany jako AnsiString ze stroną kodową UTF-8.
ShortString 255 znaków 2 bajty Tradycyjny, niezarządzany ciąg o stałej długości i bardzo małym obciążeniu
WideString 2 GB 4 bajty Przeznaczony do współdziałania COM, zarządzanego ciągu w formacie UTF-16. Odpowiednik typu Windows BSTR .

UnicodeString i AnsiStringliczone w referencjach i kopiowane przy zapisie (COW).
ShortString i WideString nie są liczone w referencjach i nie mają semantyki COW.

Smyczki

uses
  System.Character;

var
  S1, S2: string;
begin
  S1 := 'Foo';
  S2 := ToLower(S1); // Convert the string to lower-case
  S1 := ToUpper(S2); // Convert the string to upper-case

Znaki

2009
uses
  Character;

var
  C1, C2: Char;
begin
  C1 := 'F';
  C2 := ToLower(C1); // Convert the char to lower-case
  C1 := ToUpper(C2); // Convert the char to upper-case

Klauzula uses powinna mieć System.Character jeśli wersja jest w wersji XE2 lub nowszej.

Duże i małe litery

uses
  SysUtils;

var
  S1, S2: string;
begin
  S1 := 'Foo';
  S2 := LowerCase(S1); // S2 := 'foo';
  S1 := UpperCase(S2); // S1 := 'FOO';

Zadanie

Przypisywanie ciągów do różnych typów ciągów i zachowanie środowiska wykonawczego w odniesieniu do nich. Alokacja pamięci, zliczanie referencji, indeksowany dostęp do znaków i błędy kompilatora opisane krótko, w stosownych przypadkach.

var
  SS5: string[5]; {a shortstring of 5 chars + 1 length byte, no trailing `0`}
  WS: Widestring; {managed pointer, with a bit of compiler support}
  AS: ansistring; {ansistring with the default codepage of the system}
  US: unicodestring; {default string type}
  U8: UTF8string;//same as AnsiString(65001)
  A1251: ansistring(1251); {ansistring with codepage 1251: Cryllic set}
  RB: RawbyteString; {ansistring with codepage 0: no conversion set}
begin
  SS5:= 'test'; {S[0] = Length(SS254) = 4, S[1] = 't'...S[5] = undefined}
  SS5:= 'test1'; {S[0] = 5, S[5] = '1', S[6] is out of bounds}
  SS5:= 'test12'; {compile time error}
  WS:= 'test'; {WS now points to a constant unicodestring hard compiled into the data segment}
  US:= 'test'+IntToStr(1); {New unicode string is created with reference count = 1}
  WS:= US; {SysAllocateStr with datacopied to dest, US refcount = 1 !}
  AS:= US; {the UTF16 in US is converted to "extended" ascii taking into account the codepage in AS possibly losing data in the process}  
  U8:= US; {safe copy of US to U8, all data is converted from UTF16 into UTF8}
  RB:= US; {RB = 'test1'#0 i.e. conversion into RawByteString uses system default codepage}
  A1251:= RB; {no conversion takes place, only reference copied. Ref count incremented }

Liczenie referencji

Liczenie referencji na ciągach znaków jest bezpieczne dla wątków. Blokady i procedury obsługi wyjątków służą do zabezpieczenia procesu. Rozważ następujący kod z komentarzami wskazującymi, gdzie kompilator wstawia kod w czasie kompilacji, aby zarządzać liczbą referencji:

procedure PassWithNoModifier(S: string);
// prologue: Increase reference count of S (if non-negative),
//           and enter a try-finally block
begin
  // Create a new string to hold the contents of S and 'X'. Assign the new string to S,
  // thereby reducing the reference count of the string S originally pointed to and
  // brining the reference count of the new string to 1.
  // The string that S originally referred to is not modified.
  S := S + 'X';
end;
// epilogue: Enter the `finally` section and decrease the reference count of S, which is
//           now the new string. That count will be zero, so the new string will be freed.
    
procedure PassWithConst(const S: string);
var
  TempStr: string;
// prologue: Clear TempStr and enter a try-finally block. No modification of the reference
//           count of string referred to by S.
begin
  // Compile-time error: S is const.
  S := S + 'X';
  // Create a new string to hold the contents of S and 'X'. TempStr gets a reference count
  // of 1, and reference count of S remains unchanged.
  TempStr := S + 'X';
end;
// epilogue: Enter the `finally` section and decrease the reference count of TempStr,
//           freeing TempStr because its reference count will be zero.

Jak pokazano powyżej, wprowadzenie tymczasowego ciągu lokalnego do przechowywania modyfikacji parametru wiąże się z tym samym narzutem, co wprowadzanie modyfikacji bezpośrednio do tego parametru. Deklarowania ciąg const unika tylko liczenia odniesienia, gdy parametr ciąg jest naprawdę tylko do odczytu. Jednak, aby uniknąć wycieku szczegółów implementacji poza funkcją, zaleca się zawsze stosowanie jednego z parametrów const , var lub out on string.

Kodowanie

Typy ciągów, takie jak UnicodeString, AnsiString, WideString i UTF8String są przechowywane w pamięci przy użyciu ich odpowiedniego kodowania (więcej informacji na temat typów ciągów). Przypisanie jednego typu łańcucha do innego może spowodować konwersję. Ciąg znaków został zaprojektowany tak, aby był niezależny od kodowania - nigdy nie należy używać jego wewnętrznej reprezentacji.

Klasa Sysutils.TEncoding udostępnia metodę GetBytes do konwersji string na TBytes (tablica bajtów) oraz GetString do konwersji string TBytes na string . Klasa Sysutils.TEncoding zapewnia również wiele predefiniowanych kodowań jako właściwości klasy.

Jednym ze sposobów radzenia sobie z kodowaniem jest użycie tylko typu string w aplikacji i użycie TEncoding każdym razem, gdy trzeba użyć określonego kodowania - zwykle w operacjach I / O, wywołaniach DLL itp.

procedure EncodingExample;
var hello,response:string;
    dataout,datain:TBytes;
    expectedLength:integer;
    stringStream:TStringStream;
    stringList:TStringList;
     
begin
  hello := 'Hello World!Привет мир!';
  dataout := SysUtils.TEncoding.UTF8.GetBytes(hello); //Conversion to UTF8
  datain := SomeIOFunction(dataout); //This function expects input as TBytes in UTF8 and returns output as UTF8 encoded TBytes.
  response := SysUtils.TEncoding.UTF8.GetString(datain); //Convertsion from UTF8

  //In case you need to send text via pointer and length using specific encoding (used mostly for DLL calls)
  dataout := SysUtils.TEncoding.GetEncoding('ISO-8859-2').GetBytes(hello); //Conversion to ISO 8859-2
  DLLCall(addr(dataout[0]),length(dataout));
  //The same is for cases when you get text via pointer and length
  expectedLength := DLLCallToGetDataLength();
  setLength(datain,expectedLength);
  DLLCall(addr(datain[0]),length(datain));
  response := Sysutils.TEncoding.GetEncoding(1250).getString(datain);

   //TStringStream and TStringList can use encoding for I/O operations
   stringList:TStringList.create;
   stringList.text := hello;
   stringList.saveToFile('file.txt',SysUtils.TEncoding.Unicode);
   stringList.destroy;
   stringStream := TStringStream(hello,SysUtils.TEncoding.Unicode);
   stringStream.saveToFile('file2.txt');
   stringStream.Destroy;
end;


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow