📄 mandysoft.vcl.ansiclasses.pas
字号:
(* AnsiClasses - Ansi classes library
* Copyright (c) 2003 by Mandys Tomas-MandySoft
*)
{ URL: http://www.2p.cz }
unit MandySoft.Vcl.AnsiClasses;
interface
uses
Classes, System.Collections, System.Text, SysUtils;
type
{ TAnsiStrings class }
TAnsiStrings = class(TPersistent)
private
FDefined: TStringsDefined;
FDelimiter: AnsiChar;
FLineBreak: AnsiString;
FQuoteChar: AnsiChar;
FNameValueSeparator: AnsiChar;
FUpdateCount: Integer;
function GetCommaText: AnsiString;
function GetDelimitedText: AnsiString;
function GetName(Index: Integer): AnsiString;
function GetValue(const Name: AnsiString): AnsiString;
procedure ReadData(Reader: TReader);
procedure SetCommaText(const Value: AnsiString);
procedure SetDelimitedText(const Value: AnsiString);
procedure SetValue(const Name, Value: AnsiString);
procedure WriteData(Writer: TWriter);
function GetDelimiter: AnsiChar;
procedure SetDelimiter(const Value: AnsiChar);
function GetLineBreak: AnsiString;
procedure SetLineBreak(const Value: AnsiString);
function GetQuoteChar: AnsiChar;
procedure SetQuoteChar(const Value: AnsiChar);
function GetNameValueSeparator: AnsiChar;
procedure SetNameValueSeparator(const Value: AnsiChar);
function GetValueFromIndex(Index: Integer): AnsiString;
procedure SetValueFromIndex(Index: Integer; const Value: AnsiString);
protected
procedure DefineProperties(Filer: TFiler); override;
procedure Error(const Msg: string; Data: Integer); overload;
//procedure Error(Msg: PResStringRec; Data: Integer); overload;
function ExtractName(const S: AnsiString): AnsiString;
function Get(Index: Integer): AnsiString; virtual; abstract;
function GetCapacity: Integer; virtual;
function GetCount: Integer; virtual; abstract;
function GetObject(Index: Integer): TObject; virtual;
function GetTextStr: AnsiString; virtual;
procedure Put(Index: Integer; const S: AnsiString); virtual;
procedure PutObject(Index: Integer; AObject: TObject); virtual;
procedure SetCapacity(NewCapacity: Integer); virtual;
procedure SetTextStr(const Value: AnsiString); virtual;
procedure SetUpdateState(Updating: Boolean); virtual;
property UpdateCount: Integer read FUpdateCount;
function CompareStrings(const S1, S2: AnsiString): Integer; virtual;
public
function Add(const S: AnsiString): Integer; virtual;
function AddObject(const S: AnsiString; AObject: TObject): Integer; virtual;
procedure Append(const S: AnsiString);
procedure AddStrings(Strings: TAnsiStrings); virtual;
procedure Assign(Source: TPersistent); override;
procedure BeginUpdate;
procedure Clear; virtual; abstract;
procedure Delete(Index: Integer); virtual; abstract;
procedure EndUpdate;
function Equals(Strings: TAnsiStrings): Boolean;
procedure Exchange(Index1, Index2: Integer); virtual;
function IndexOf(const S: AnsiString): Integer; virtual;
function IndexOfName(const Name: AnsiString): Integer; virtual;
function IndexOfObject(AObject: TObject): Integer; virtual;
procedure Insert(Index: Integer; const S: AnsiString); virtual; abstract;
procedure InsertObject(Index: Integer; const S: AnsiString;
AObject: TObject); virtual;
procedure LoadFromFile(const FileName: AnsiString); overload; virtual;
procedure LoadFromFile(const FileName: AnsiString; Encoding: System.Text.Encoding); overload; virtual;
procedure LoadFromStream(Stream: TStream); overload; virtual;
procedure LoadFromStream(Stream: TStream; Encoding: System.Text.Encoding); overload; virtual;
procedure Move(CurIndex, NewIndex: Integer); virtual;
procedure SaveToFile(const FileName: AnsiString); overload; virtual;
procedure SaveToFile(const FileName: AnsiString; Encoding: System.Text.Encoding); overload; virtual;
procedure SaveToStream(Stream: TStream); overload; virtual;
procedure SaveToStream(Stream: TStream; Encoding: System.Text.Encoding); overload; virtual;
property Capacity: Integer read GetCapacity write SetCapacity;
property CommaText: AnsiString read GetCommaText write SetCommaText;
property Count: Integer read GetCount;
property Delimiter: AnsiChar read GetDelimiter write SetDelimiter;
property DelimitedText: AnsiString read GetDelimitedText write SetDelimitedText;
property LineBreak: AnsiString read GetLineBreak write SetLineBreak;
property Names[Index: Integer]: AnsiString read GetName;
property Objects[Index: Integer]: TObject read GetObject write PutObject;
property QuoteChar: AnsiChar read GetQuoteChar write SetQuoteChar;
property Values[const Name: AnsiString]: AnsiString read GetValue write SetValue;
property ValueFromIndex[Index: Integer]: AnsiString read GetValueFromIndex write SetValueFromIndex;
property NameValueSeparator: AnsiChar read GetNameValueSeparator write SetNameValueSeparator;
property Strings[Index: Integer]: AnsiString read Get write Put; default;
property Text: AnsiString read GetTextStr write SetTextStr;
end;
{ TTStringList class }
TAnsiStringList = class;
TAnsiStringItem = record
FString: AnsiString;
FObject: TObject;
end;
TAnsiStringListSortCompare = function(List: TAnsiStringList; Index1, Index2: Integer): Integer;
TAnsiStringList = class(TAnsiStrings)
private
FList: array of TAnsiStringItem;
FCount: Integer;
FSorted: Boolean;
FDuplicates: TDuplicates;
FCaseSensitive: Boolean;
FOnChange: TNotifyEvent;
FOnChanging: TNotifyEvent;
procedure ExchangeItems(Index1, Index2: Integer);
procedure Grow;
procedure QuickSort(L, R: Integer; SCompare: TAnsiStringListSortCompare);
procedure SetSorted(Value: Boolean);
procedure SetCaseSensitive(const Value: Boolean);
protected
procedure Changed; virtual;
procedure Changing; virtual;
function Get(Index: Integer): AnsiString; override;
function GetCapacity: Integer; override;
function GetCount: Integer; override;
function GetObject(Index: Integer): TObject; override;
procedure Put(Index: Integer; const S: AnsiString); override;
procedure PutObject(Index: Integer; AObject: TObject); override;
procedure SetCapacity(NewCapacity: Integer); override;
procedure SetUpdateState(Updating: Boolean); override;
function CompareStrings(const S1, S2: AnsiString): Integer; override;
procedure InsertItem(Index: Integer; const S: AnsiString; AObject: TObject); virtual;
public
function Add(const S: AnsiString): Integer; override;
function AddObject(const S: AnsiString; AObject: TObject): Integer; override;
procedure Clear; override;
procedure Delete(Index: Integer); override;
procedure Exchange(Index1, Index2: Integer); override;
function Find(const S: AnsiString; var Index: Integer): Boolean; virtual;
function IndexOf(const S: AnsiString): Integer; override;
procedure Insert(Index: Integer; const S: AnsiString); override;
procedure InsertObject(Index: Integer; const S: AnsiString;
AObject: TObject); override;
procedure Sort; virtual;
procedure CustomSort(Compare: TAnsiStringListSortCompare); virtual;
property Duplicates: TDuplicates read FDuplicates write FDuplicates;
property Sorted: Boolean read FSorted write SetSorted;
property CaseSensitive: Boolean read FCaseSensitive write SetCaseSensitive;
property OnChange: TNotifyEvent read FOnChange write FOnChange;
property OnChanging: TNotifyEvent read FOnChanging write FOnChanging;
end;
implementation
uses
RTLConsts;
{ TAnsiStrings }
function TAnsiStrings.Add(const S: AnsiString): Integer;
begin
Result := GetCount;
Insert(Result, S);
end;
function TAnsiStrings.AddObject(const S: AnsiString; AObject: TObject): Integer;
begin
Result := Add(S);
PutObject(Result, AObject);
end;
procedure TAnsiStrings.Append(const S: AnsiString);
begin
Add(S);
end;
procedure TAnsiStrings.AddStrings(Strings: TAnsiStrings);
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 TAnsiStrings.Assign(Source: TPersistent);
begin
if Source is TAnsiStrings then
begin
BeginUpdate;
try
Clear;
FDefined := TAnsiStrings(Source).FDefined;
FNameValueSeparator := TAnsiStrings(Source).FNameValueSeparator;
FQuoteChar := TAnsiStrings(Source).FQuoteChar;
FDelimiter := TAnsiStrings(Source).FDelimiter;
FLineBreak := TAnsiStrings(Source).FLineBreak;
AddStrings(TAnsiStrings(Source));
finally
EndUpdate;
end;
Exit;
end;
inherited Assign(Source);
end;
procedure TAnsiStrings.BeginUpdate;
begin
if FUpdateCount = 0 then
SetUpdateState(True);
Inc(FUpdateCount);
end;
procedure TAnsiStrings.DefineProperties(Filer: TFiler);
function DoWrite: Boolean;
begin
if Filer.Ancestor <> nil then
begin
Result := True;
if Filer.Ancestor is TAnsiStrings then
Result := not Equals(TAnsiStrings(Filer.Ancestor))
end
else
Result := Count > 0;
end;
begin
Filer.DefineProperty('Strings', ReadData, WriteData, DoWrite);
end;
procedure TAnsiStrings.EndUpdate;
begin
Dec(FUpdateCount);
if FUpdateCount = 0 then
SetUpdateState(False);
end;
function TAnsiStrings.Equals(Strings: TAnsiStrings): 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 TAnsiStrings.Error(const Msg: string; Data: Integer);
begin
raise EStringListError.CreateFmt(Msg, [Data]);
end;
{
procedure TAnsiStrings.Error(Msg: PResStringRec; Data: Integer);
begin
Error(LoadResString(Msg), Data);
end;
}
procedure TAnsiStrings.Exchange(Index1, Index2: Integer);
var
TempObject: TObject;
TempString: AnsiString;
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 TAnsiStrings.ExtractName(const S: AnsiString): AnsiString;
var
P: Integer;
begin
Result := S;
P := Pos(NameValueSeparator, Result);
if P <> 0 then
SetLength(Result, P-1)
else
SetLength(Result, 0);
end;
function TAnsiStrings.GetCapacity: Integer;
begin // descendants may optionally override/replace this default implementation
Result := Count;
end;
function TAnsiStrings.GetCommaText: AnsiString;
var
LOldDefined: TStringsDefined;
LOldDelimiter: AnsiChar;
LOldQuoteChar: AnsiChar;
begin
LOldDefined := FDefined;
LOldDelimiter := FDelimiter;
LOldQuoteChar := FQuoteChar;
Delimiter := AnsiChar(',');
QuoteChar := AnsiChar('"');
try
Result := GetDelimitedText;
finally
FDelimiter := LOldDelimiter;
FQuoteChar := LOldQuoteChar;
FDefined := LOldDefined;
end;
end;
function TAnsiStrings.GetDelimitedText: AnsiString;
var
S, D: AnsiString;
P: Integer;
I, Count, L: Integer;
begin
Count := GetCount;
if (Count = 1) and (Get(0) = '') then
Result := QuoteChar + QuoteChar
else
begin
Result := '';
D := '';
for I := 0 to Count - 1 do
begin
S := Get(I);
L := Length(S);
P := 1;
while (P <= L) and not(S[P] in [AnsiChar(#0)..AnsiChar(' ')])
and (S[P] <> QuoteChar) and (S[P] <> Delimiter) do
Inc(P);
if (P <= L) then
S := AnsiQuotedStr(S, QuoteChar);
Result := Result + D + S;
D := Delimiter;
end;
end;
end;
function TAnsiStrings.GetName(Index: Integer): AnsiString;
begin
Result := ExtractName(Get(Index));
end;
function TAnsiStrings.GetObject(Index: Integer): TObject;
begin
Result := nil;
end;
function TAnsiStrings.GetTextStr: AnsiString;
var
Buffer: StringBuilder;
I, Count: Integer;
begin
Count := GetCount;
Buffer := StringBuilder.Create;
for I := 0 to Count - 1 do
begin
Buffer.Append(Get(I));
Buffer.Append(LineBreak);
end;
Result := Buffer.ToString;
end;
function TAnsiStrings.GetValue(const Name: AnsiString): AnsiString;
var
I: Integer;
begin
I := IndexOfName(Name);
if I >= 0 then
Result := Copy(Get(I), Length(Name) + 2, MaxInt)
else
Result := '';
end;
function TAnsiStrings.IndexOf(const S: AnsiString): Integer;
begin
for Result := 0 to GetCount - 1 do
if CompareStrings(Get(Result), S) = 0 then
Exit;
Result := -1;
end;
function TAnsiStrings.IndexOfName(const Name: AnsiString): Integer;
var
P: Integer;
S: AnsiString;
begin
for Result := 0 to GetCount - 1 do
begin
S := Get(Result);
P := Pos(NameValueSeparator, S);
if (P <> 0) and (CompareStrings(Copy(S, 1, P - 1), Name) = 0) then
Exit;
end;
Result := -1;
end;
function TAnsiStrings.IndexOfObject(AObject: TObject): Integer;
begin
for Result := 0 to GetCount - 1 do
if GetObject(Result) = AObject then
Exit;
Result := -1;
end;
procedure TAnsiStrings.InsertObject(Index: Integer; const S: AnsiString;
AObject: TObject);
begin
Insert(Index, S);
PutObject(Index, AObject);
end;
procedure TAnsiStrings.LoadFromFile(const FileName: AnsiString);
begin
LoadFromFile(FileName, nil);
end;
procedure TAnsiStrings.LoadFromFile(const FileName: AnsiString; Encoding: System.Text.Encoding);
var
Stream: TStream;
begin
Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
try
LoadFromStream(Stream, Encoding);
finally
Stream.Free;
end;
end;
procedure TAnsiStrings.LoadFromStream(Stream: TStream);
begin
LoadFromStream(Stream, nil);
end;
procedure TAnsiStrings.LoadFromStream(Stream: TStream; Encoding: System.Text.Encoding);
function ContainsPreamble(Buffer, Signature: array of Byte): Boolean;
var
I: Integer;
begin
Result := True;
if Length(Buffer) >= Length(Signature) then
begin
for I := 1 to Length(Signature) do
if Buffer[I - 1] <> Signature [I - 1] then
begin
Result := False;
Break;
end;
end
else
Result := False;
end;
var
Size: Integer;
Buffer, Preamble: array of Byte;
begin
BeginUpdate;
try
// Read bytes from stream
Size := Stream.Size - Stream.Position;
SetLength(Buffer, Size);
Stream.Read(Buffer, Size);
Size := 0;
if Encoding = nil then
begin
// Find the appropraite encoding
if ContainsPreamble(Buffer, System.Text.Encoding.Unicode.GetPreamble) then
Encoding := System.Text.Encoding.Unicode
else
if ContainsPreamble(Buffer, System.Text.Encoding.BigEndianUnicode.GetPreamble) then
Encoding := System.Text.Encoding.BigEndianUnicode
else
if ContainsPreamble(Buffer, System.Text.Encoding.UTF8.GetPreamble) then
Encoding := System.Text.Encoding.UTF8
else
Encoding := System.Text.Encoding.Default;
Size := Length(Encoding.GetPreamble);
end
else
begin
// Use specified encoding, ignore preamble bytes if present
Preamble := Encoding.GetPreamble;
if ContainsPreamble(Buffer, Preamble) then
Size := Length(Preamble);
end;
SetTextStr(Encoding.GetString(Buffer, Size, Length(Buffer) - Size));
finally
EndUpdate;
end;
end;
procedure TAnsiStrings.Move(CurIndex, NewIndex: Integer);
var
TempObject: TObject;
TempString: AnsiString;
begin
if CurIndex <> NewIndex then
begin
BeginUpdate;
try
TempString := Get(CurIndex);
TempObject := GetObject(CurIndex);
Delete(CurIndex);
InsertObject(NewIndex, TempString, TempObject);
finally
EndUpdate;
end;
end;
end;
procedure TAnsiStrings.Put(Index: Integer; const S: AnsiString);
var
TempObject: TObject;
begin
TempObject := GetObject(Index);
Delete(Index);
InsertObject(Index, S, TempObject);
end;
procedure TAnsiStrings.PutObject(Index: Integer; AObject: TObject);
begin
end;
procedure TAnsiStrings.ReadData(Reader: TReader);
begin
Reader.ReadListBegin;
BeginUpdate;
try
Clear;
while not Reader.EndOfList do
Add(Reader.ReadString);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -