这是应群友的要求写的一段代码,用于将 Delphi 源码中 resourcestring 定义的资源字符串解析出来。
uses qstring;
type
TPascalResourceStringParser = class
private
function GetItems(const AIdx: Integer): QStringW;
function GetCount: Integer;
function GetNames(const AIdx: Integer): QStringW;
function GetValues(const AIdx: Integer): QStringW;
protected
FItems: TStringList;
public
constructor Create; overload;
destructor Destroy; override;
procedure Parse(S: QStringW);
property Items[const AIdx: Integer]: QStringW read GetItems;
property Names[const AIdx: Integer]: QStringW read GetNames;
property Values[const AIdx: Integer]: QStringW read GetValues;
property Count: Integer read GetCount;
end;
{ TPascalResourceStringParser }
constructor TPascalResourceStringParser.Create;
begin
FItems := TStringList.Create;
end;
destructor TPascalResourceStringParser.Destroy;
begin
FreeAndNil(FItems);
inherited;
end;
function TPascalResourceStringParser.GetCount: Integer;
begin
Result := FItems.Count;
end;
function TPascalResourceStringParser.GetItems(const AIdx: Integer): String;
begin
Result := FItems[AIdx];
end;
function TPascalResourceStringParser.GetNames(const AIdx: Integer): QStringW;
begin
Result := FItems.Names[AIdx];
end;
function TPascalResourceStringParser.GetValues(const AIdx: Integer): QStringW;
function DecodeString(S: QStringW): QStringW;
var
ps, pd: PWideChar;
V: Int64;
AIntToChar: Boolean;
begin
if Length(S) > 0 then
begin
ps := PWideChar(S);
SkipSpaceW(ps);
SetLength(Result, Length(S));
pd := PWideChar(Result);
while ps^ <> #0 do
begin
if ps^ = '''' then
begin
Inc(ps);
while ps^ <> '''' do
begin
pd^ := ps^;
Inc(pd);
Inc(ps);
end;
Inc(ps);
end
else
begin
if ps^ = '#' then
begin
Inc(ps);
AIntToChar := true;
end
else if StartWithW(ps, 'char', true) then
begin
Inc(ps, 4);
SkipSpaceW(ps);
if ps^ = '(' then
begin
Inc(ps);
SkipSpaceW(ps);
AIntToChar := true;
end;
end
else if StartWithW(ps, 'chr', true) then
begin
Inc(ps, 3);
SkipSpaceW(ps);
if ps^ = '(' then
begin
Inc(ps);
SkipSpaceW(ps);
AIntToChar := true;
end;
end
else
AIntToChar := false;
if AIntToChar then
begin
if ParseInt(ps, V) > 0 then
begin
pd^ := WideChar(V);
Inc(pd);
end;
end
else
Inc(ps);
end;
end;
SetLength(Result, pd - PWideChar(Result));
end
else
Result := '';
end;
begin
Result := DecodeString(FItems.ValueFromIndex[AIdx]);
end;
procedure TPascalResourceStringParser.Parse(S: QStringW);
var
AHelper: TQStringCatHelperW;
ps, pl: PQCharW;
ALine: QStringW;
ALn: Integer;
AStarted: Boolean;
function DecodeStatement: QStringW;
var
AQuoter: QCharW;
begin
SkipSpaceW(ps);
AHelper.Position := 0;
while ps^ <> #0 do
begin
// 跳过行注释
if (ps[0] = '/') and (ps[1] = '/') then
SkipLineW(ps)
// 跳过块注释
else if ps[0] = '{' then
begin
SkipUntilW(ps, '}');
Inc(ps);
end
// 另一种块注释
else if (ps[0] = '(') and (ps[0] = '*') then
begin
repeat
SkipUntilW(ps, '*');
if ps^ = '*' then
Inc(ps);
until (ps^ = ')') or (ps^ = #0);
if ps^ = ')' then
Inc(ps);
end
else if ps^ = '''' then
begin
AHelper.Cat(ps^);
AQuoter := ps^;
Inc(ps);
while ps^ <> #0 do
begin
AHelper.Cat(ps^);
if ps^ = '''' then
begin
Inc(ps);
if ps^ <> '''' then
Break
else
Inc(ps);
end
else
Inc(ps);
end;
end
else if ps^ = ';' then // 语句结束
begin
Result := AHelper.Value;
Inc(ps);
SkipSpaceW(ps);
Break;
end
else
begin
if Ord(ps^) in [9, 10, 13, 32] then
begin
if AHelper.Position > 0 then
begin
if AHelper.Chars[AHelper.Position - 1] <> ' ' then
AHelper.Cat(' ');
end;
end
else
AHelper.Cat(ps^);
Inc(ps);
end;
end;
SkipSpaceW(ps);
end;
begin
AHelper := TQStringCatHelperW.Create;
FItems.Clear;
try
ps := PQCharW(S);
ALn := 0;
AStarted := false;
while ps^ <> #0 do
begin
ALine := DecodeStatement;
pl := PQCharW(ALine);
if StartWithW(pl, 'interface ', true) then
begin
ALine := DeleteLeftW(ALine, 'interface ', true);
AStarted := false;
end
else if StartWithW(pl, 'implementation ', true) then
begin
ALine := DeleteLeftW(ALine, 'implementation ', true);
AStarted := false;
end;
pl := PQCharW(ALine);
if StartWithW(pl, 'resourcestring ', true) then
begin
AStarted := true;
ALine := DeleteLeftW(ALine, 'resourcestring ', true);
end
else if AStarted then
AStarted := not(StartWithW(pl, 'var ', true) or StartWithW(pl,
'function ', true) or StartWithW(pl, 'type ', true) or StartWithW(pl,
'const ', true) or StartWithW(pl, 'uses ', true));;
if AStarted then
begin
FItems.Add(ALine);
// DebugOut('Line %d:%s', [ALn, ALine]);
Inc(ALn);
end;
end;
finally
FreeAndNil(AHelper);
FItems.EndUpdate;
end;
end;留此存念,同时分享给大家,有用的就拿去用。
