📄 wstrlist.pas
字号:
unit WStrList;
interface
uses
SysUtils, Windows, Classes, Langs;
type
{ TWideStrings class }
{$WARNINGS OFF}
TWideStrings = class(TStrings)
private
FUpdateCount: Integer;
FLanguage: TLanguage;
function GetCommaText: WideString;
function GetName(Index: Integer): WideString;
function GetValue(const Name: WideString): WideString;
procedure ReadData(Reader: TReader);
procedure SetCommaText(const Value: WideString);
procedure SetValue(const Name, Value: WideString);
procedure WriteData(Writer: TWriter);
protected
procedure DefineProperties(Filer: TFiler); override;
procedure Error(const Msg: string; Data: Integer);
function Get(Index: Integer): WideString; virtual; abstract;
function GetCapacity: Integer; virtual;
function GetCount: Integer; virtual; abstract;
function GetObject(Index: Integer): TObject; virtual;
function GetTextStr: WideString; virtual;
procedure Put(Index: Integer; const S: WideString); virtual;
procedure PutObject(Index: Integer; AObject: TObject); virtual;
procedure SetCapacity(NewCapacity: Integer); virtual;
procedure SetTextStr(const Value: WideString); virtual;
procedure SetUpdateState(Updating: Boolean); virtual;
procedure SetLanguage(Value: TLanguage); virtual;
function GetLanguage: TLanguage; virtual;
public
constructor Create;
function Add(const S: WideString): Integer; virtual;
function AddObject(const S: WideString; AObject: TObject): Integer; virtual;
procedure Append(const S: WideString);
procedure AddStrings(Strings: TWideStrings); virtual;
procedure Assign(Source: TPersistent); override;
procedure BeginUpdate;
procedure Clear; virtual; abstract;
procedure Delete(Index: Integer); virtual; abstract;
procedure EndUpdate;
function Equals(Strings: TWideStrings): Boolean;
procedure Exchange(Index1, Index2: Integer); virtual;
function GetText: PWideChar; virtual;
function IndexOf(const S: WideString): Integer; virtual;
function IndexOfName(const Name: WideString): Integer;
function IndexOfObject(AObject: TObject): Integer;
procedure Insert(Index: Integer; const S: WideString); virtual; abstract;
procedure InsertObject(Index: Integer; const S: WideString;
AObject: TObject);
procedure LoadFromFile(const FileName: string); virtual;
procedure LoadFromStream(Stream: TStream); virtual;
procedure Move(CurIndex, NewIndex: Integer); virtual;
procedure SaveToFile(const FileName: string); virtual;
procedure SaveToStream(Stream: TStream); virtual;
procedure SetText(Text: PWideChar); virtual;
property Capacity: Integer read GetCapacity write SetCapacity;
property CommaText: WideString read GetCommaText write SetCommaText;
property Count: Integer read GetCount;
property Names[Index: Integer]: WideString read GetName;
property Objects[Index: Integer]: TObject read GetObject write PutObject;
property Values[const Name: WideString]: WideString read GetValue write SetValue;
property Strings[Index: Integer]: WideString read Get write Put; default;
property Text: WideString read GetTextStr write SetTextStr;
property Language: TLanguage read GetLanguage write SetLanguage;
end;
{ TWideStringList class }
PWideStringItem = ^TWideStringItem;
TWideStringItem = record
FString: WideString;
FObject: TObject;
end;
PWideStringItemList = ^TWideStringItemList;
TWideStringItemList = array[0..MaxListSize] of TWideStringItem;
TWideStringList = class(TWideStrings)
private
FList: PStringItemList;
FCount: Integer;
FCapacity: Integer;
FSorted: Boolean;
FDuplicates: TDuplicates;
FOnChange: TNotifyEvent;
FOnChanging: TNotifyEvent;
procedure ExchangeItems(Index1, Index2: Integer);
procedure Grow;
procedure QuickSort(L, R: Integer);
procedure InsertItem(Index: Integer; const S: WideString);
procedure SetSorted(Value: Boolean);
protected
procedure Changed; virtual;
procedure Changing; virtual;
function Get(Index: Integer): WideString; override;
function GetCapacity: Integer; override;
function GetCount: Integer; override;
function GetObject(Index: Integer): TObject; override;
procedure Put(Index: Integer; const S: WideString); override;
procedure PutObject(Index: Integer; AObject: TObject); override;
procedure SetCapacity(NewCapacity: Integer); override;
procedure SetUpdateState(Updating: Boolean); override;
procedure SetLanguage(Value: TLanguage); override;
public
destructor Destroy; override;
function Add(const S: WideString): Integer; override;
procedure Clear; override;
procedure Delete(Index: Integer); override;
procedure Exchange(Index1, Index2: Integer); override;
function Find(const S: WideString; var Index: Integer): Boolean; virtual;
function IndexOf(const S: WideString): Integer; override;
procedure Insert(Index: Integer; const S: WideString); override;
procedure Sort; virtual;
property Duplicates: TDuplicates read FDuplicates write FDuplicates;
property Sorted: Boolean read FSorted write SetSorted;
property OnChange: TNotifyEvent read FOnChange write FOnChange;
property OnChanging: TNotifyEvent read FOnChanging write FOnChanging;
end;
{$WARNINGS ON}
function WideQuotedStr(const S: WideString; Quote: WideChar): WideString;
function WideExtractQuotedStr(var Src: PWideChar; Quote: WideChar): WideString;
implementation
uses
RTLConsts, Consts;
type
TCompareFunc = function (W1, W2: WideString; Locale: LCID): Integer;
var
WideCompareText: TCompareFunc;
const
BOM: Word = $FFFE; // Byte Order Mark
function WideStrScan(Str: PWideChar; Chr: WideChar): PWideChar; assembler;
asm
PUSH EDI
PUSH EAX
MOV EDI,Str
MOV ECX,0FFFFFFFFH
XOR AX,AX
REPNE SCASW
NOT ECX
POP EDI
MOV AX,Chr
REPNE SCASW
MOV EAX,0
JNE @@1
MOV EAX,EDI
DEC EAX
@@1: POP EDI
end;
function WideStrEnd(Str: PWideChar): PWideChar; assembler;
asm
MOV EDX,EDI
MOV EDI,EAX
MOV ECX,0FFFFFFFFH
XOR AX,AX
REPNE SCASW
LEA EAX,[EDI-1]
MOV EDI,EDX
end;
function WideQuotedStr(const S: WideString; Quote: WideChar): WideString;
var
P, Src, Dest: PWideChar;
AddCount: Integer;
begin
AddCount := 0;
P := WideStrScan(PWideChar(S), Quote);
while P <> nil do
begin
Inc(P);
Inc(AddCount);
P := WideStrScan(P, Quote);
end;
if AddCount = 0 then
begin
Result := WideString(Quote) + S + WideString(Quote);
Exit;
end;
SetLength(Result, Length(S) + AddCount + 2);
Dest := Pointer(Result);
Dest^ := Quote;
Inc(Dest);
Src := Pointer(S);
P := WideStrScan(Src, Quote);
repeat
Inc(P);
Move(Src^, Dest^, P - Src);
Inc(Dest, P - Src);
Dest^ := Quote;
Inc(Dest);
Src := P;
P := WideStrScan(Src, Quote);
until P = nil;
P := WideStrEnd(Src);
Move(Src^, Dest^, P - Src);
Inc(Dest, P - Src);
Dest^ := Quote;
end;
function WideExtractQuotedStr(var Src: PWideChar; Quote: WideChar): WideString;
var
P, Dest: PWideChar;
DropCount: Integer;
begin
Result := '';
if (Src = nil) or (Src^ <> Quote) then Exit;
Inc(Src);
DropCount := 1;
P := Src;
Src := WideStrScan(Src, Quote);
while Src <> nil do // count adjacent pairs of quote chars
begin
Inc(Src);
if Src^ <> Quote then Break;
Inc(Src);
Inc(DropCount);
Src := WideStrScan(Src, Quote);
end;
if Src = nil then Src := WideStrEnd(P);
if ((Src - P) <= 1) then Exit;
if DropCount = 1 then
SetString(Result, P, Src - P - 1)
else
begin
SetLength(Result, Src - P - DropCount);
Dest := PWideChar(Result);
Src := WideStrScan(P, Quote);
while Src <> nil do
begin
Inc(Src);
if Src^ <> Quote then Break;
Move(P^, Dest^, Src - P);
Inc(Dest, Src - P);
Inc(Src);
P := Src;
Src := WideStrScan(Src, Quote);
end;
if Src = nil then Src := WideStrEnd(P);
Move(P^, Dest^, Src - P - 1);
end;
end;
function CompareTextWin95(W1, W2: WideString; Locale: LCID): Integer;
var
S1, S2: string;
CP: Integer;
L1, L2: Integer;
begin
L1:= Length(W1);
L2:= Length(W2);
SetLength(S1, L1);
SetLength(S2, L2);
CP:= CodePageFromLocale(Locale);
WideCharToMultiByte(CP, 0, @W1[1], L1, @S1[1], L1, nil, nil);
WideCharToMultiByte(CP, 0, @W2[1], L2, @S2[1], L2, nil, nil);
Result:= CompareStringA(Locale, NORM_IGNORECASE, @S1[1], Length(S1),
@S2[1], Length(S2)) - 2;
end;
function CompareTextWinNT(W1, W2: WideString; Locale: LCID): Integer;
begin
Result:= CompareStringW(Locale, NORM_IGNORECASE, @W1[1], Length(W1),
@W2[1], Length(W2)) - 2;
end;
constructor TWideStrings.Create;
begin
inherited;
FLanguage:= GetUserDefaultLCID;
end;
procedure TWideStrings.SetLanguage(Value: TLanguage);
begin
FLanguage:= Value;
end;
function TWideStrings.Add(const S: WideString): Integer;
begin
Result := GetCount;
Insert(Result, S);
end;
function TWideStrings.AddObject(const S: WideString; AObject: TObject): Integer;
begin
Result := Add(S);
PutObject(Result, AObject);
end;
procedure TWideStrings.Append(const S: WideString);
begin
Add(S);
end;
procedure TWideStrings.AddStrings(Strings: TWideStrings);
var
I: Integer;
begin
BeginUpdate;
try
for I := 0 to Strings.Count - 1 do
AddObject(Strings[I], Strings.Objects[I]);
finally
EndUpdate;
end;
end;
procedure TWideStrings.Assign(Source: TPersistent);
var
I: Integer;
begin
if Source is TWideStrings then
begin
BeginUpdate;
try
Clear;
AddStrings(TWideStrings(Source));
finally
EndUpdate;
end;
Exit;
end
else if Source is TStrings then
begin
BeginUpdate;
try
for I := 0 to TStrings(Source).Count - 1 do
AddObject(TStrings(Source)[I], TStrings(Source).Objects[I]);
finally
EndUpdate;
end;
end;
inherited Assign(Source);
end;
procedure TWideStrings.BeginUpdate;
begin
if FUpdateCount = 0 then SetUpdateState(True);
Inc(FUpdateCount);
end;
procedure TWideStrings.DefineProperties(Filer: TFiler);
function DoWrite: Boolean;
begin
if Filer.Ancestor <> nil then
begin
Result := True;
if Filer.Ancestor is TWideStrings then
Result := not Equals(TWideStrings(Filer.Ancestor))
end
else Result := Count > 0;
end;
begin
Filer.DefineProperty('WideStrings', ReadData, WriteData, DoWrite);
end;
procedure TWideStrings.EndUpdate;
begin
Dec(FUpdateCount);
if FUpdateCount = 0 then SetUpdateState(False);
end;
function TWideStrings.Equals(Strings: TWideStrings): Boolean;
var
I, Count: Integer;
begin
Result := False;
Count := GetCount;
if Count <> Strings.GetCount then Exit;
for I := 0 to Count - 1 do if Get(I) <> Strings.Get(I) then Exit;
Result := True;
end;
procedure TWideStrings.Error(const Msg: string; Data: Integer);
function ReturnAddr: Pointer;
asm
MOV EAX,[EBP+4]
end;
begin
raise EStringListError.CreateFmt(Msg, [Data]) at ReturnAddr;
end;
procedure TWideStrings.Exchange(Index1, Index2: Integer);
var
TempObject: TObject;
TempString: WideString;
begin
BeginUpdate;
try
TempString := Strings[Index1];
TempObject := Objects[Index1];
Strings[Index1] := Strings[Index2];
Objects[Index1] := Objects[Index2];
Strings[Index2] := TempString;
Objects[Index2] := TempObject;
finally
EndUpdate;
end;
end;
function TWideStrings.GetCapacity: Integer;
begin // descendants may optionally override/replace this default implementation
Result := Count;
end;
function TWideStrings.GetCommaText: WideString;
var
S: WideString;
P: PWideChar;
I, Count: Integer;
begin
Count := GetCount;
if (Count = 1) and (Get(0) = '') then
Result := '""'
else
begin
Result := '';
for I := 0 to Count - 1 do
begin
S := Get(I);
P := PWideChar(S);
while not (P^ in [WideChar(#0)..WideChar(' '),WideChar('"'),WideChar(',')]) do
P := CharNextW(P);
if (P^ <> #0) then S := WideQuotedStr(S, '"');
Result := Result + S + ',';
end;
System.Delete(Result, Length(Result), 1);
end;
end;
function TWideStrings.GetName(Index: Integer): WideString;
var
P: Integer;
begin
Result := Get(Index);
P:= 1;
while Result[P]<>'=' do
Inc(P);
if P <> 0 then
SetLength(Result, P-1) else
SetLength(Result, 0);
end;
function TWideStrings.GetObject(Index: Integer): TObject;
begin
Result := nil;
end;
function TWideStrings.GetText: PWideChar;
var
TempStr: WideString;
begin
TempStr:= GetTextStr;
Result := AllocMem(2*Length(TempStr)+10);
System.Move(TempStr[1], Result^, 2*Length(TempStr)+2);
end;
function TWideStrings.GetTextStr: WideString;
var
I, L, Size, Count: Integer;
P: PWideChar;
S: WideString;
begin
Count := GetCount;
Size := 0;
for I := 0 to Count - 1 do Inc(Size, Length(Get(I)) + 2);
SetString(Result, nil, Size);
P := Pointer(Result);
for I := 0 to Count - 1 do
begin
S := Get(I);
L := Length(S);
if L <> 0 then
begin
System.Move(Pointer(S)^, P^, L*2);
Inc(P, L);
end;
P^ := #13;
Inc(P);
P^ := #10;
Inc(P);
end;
end;
function TWideStrings.GetValue(const Name: WideString): WideString;
var
I: Integer;
begin
I := IndexOfName(Name);
if I >= 0 then
Result := Copy(Get(I), Length(Name) + 2, MaxInt) else
Result := '';
end;
function TWideStrings.IndexOf(const S: WideString): Integer;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -