Added: TNamedFormatStringList
Changed: NamedFormat now requires names to be enclosed in <> (mainly for readability, partially because it makes parsing more reliable)
This commit is contained in:
parent
263c324676
commit
4cab1f15b4
@ -9,22 +9,39 @@
|
|||||||
unit X2UtNamedFormat;
|
unit X2UtNamedFormat;
|
||||||
|
|
||||||
interface
|
interface
|
||||||
|
uses
|
||||||
|
Classes;
|
||||||
|
|
||||||
|
|
||||||
|
type
|
||||||
|
TNamedFormatStringList = class(TStringList)
|
||||||
|
public
|
||||||
|
procedure AddLn();
|
||||||
|
|
||||||
|
function Format(AParams: array of const): String;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
AFormat uses the same format strings as SysUtils.Format, where each
|
AFormat uses the same format strings as SysUtils.Format, where each
|
||||||
format specifier may use a named instead of a numeric index.
|
format specifier may use a named instead of a numeric index, surrounded by
|
||||||
|
<>, eg:
|
||||||
|
|
||||||
|
%<Value1>:s %<Value2>:.2d
|
||||||
|
|
||||||
|
|
||||||
AParams contains alternating the parameter name and it's value.
|
AParams contains alternating the parameter name and it's value.
|
||||||
|
|
||||||
Note: NamedFormat works by mapping names to indices and passing the result
|
Note: NamedFormat works by mapping names to indices and passing the result
|
||||||
to SysUtils.Format. Unnamed specifiers will therefore be affected by
|
to SysUtils.Format. Unnamed or existing indexed specifiers will therefore
|
||||||
named specifiers! It is recommended to name all specifiers.
|
be affected by named specifiers! It is strongly recommended to name all
|
||||||
|
specifiers.
|
||||||
}
|
}
|
||||||
function NamedFormat(const AFormat: String; AParams: array of const): String;
|
function NamedFormat(const AFormat: String; AParams: array of const): String;
|
||||||
|
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
uses
|
uses
|
||||||
Classes,
|
|
||||||
SysUtils;
|
SysUtils;
|
||||||
|
|
||||||
|
|
||||||
@ -34,7 +51,9 @@ type
|
|||||||
|
|
||||||
const
|
const
|
||||||
SpecifierChar = '%';
|
SpecifierChar = '%';
|
||||||
ValidNameChars = ['A'..'Z', 'a'..'z', '0'..'9'];
|
SpecifierNameStart = '<';
|
||||||
|
SpecifierNameEnd = '>';
|
||||||
|
ValidNameChars = ['A'..'Z', 'a'..'z', '0'..'9', '_'];
|
||||||
|
|
||||||
|
|
||||||
procedure StreamWriteChar(const AStream: TStream; const AValue: Char);
|
procedure StreamWriteChar(const AStream: TStream; const AValue: Char);
|
||||||
@ -59,7 +78,7 @@ begin
|
|||||||
|
|
||||||
while position < AEnd do
|
while position < AEnd do
|
||||||
begin
|
begin
|
||||||
if position^ = ':' then
|
if position^ = SpecifierNameEnd then
|
||||||
begin
|
begin
|
||||||
Result := position;
|
Result := position;
|
||||||
break;
|
break;
|
||||||
@ -116,9 +135,11 @@ begin
|
|||||||
StreamWriteChar(formatStream, currentPos^);
|
StreamWriteChar(formatStream, currentPos^);
|
||||||
Inc(currentPos);
|
Inc(currentPos);
|
||||||
|
|
||||||
{ Check if this is not an escape character }
|
{ Check if this is indeed a named specifier }
|
||||||
if (currentPos < formatEnd) and (currentPos^ <> SpecifierChar) then
|
if (currentPos < formatEnd) and (currentPos^ = SpecifierNameStart) then
|
||||||
begin
|
begin
|
||||||
|
Inc(currentPos);
|
||||||
|
|
||||||
nameStart := currentPos;
|
nameStart := currentPos;
|
||||||
nameEnd := FindNameEnd(currentPos, formatEnd);
|
nameEnd := FindNameEnd(currentPos, formatEnd);
|
||||||
|
|
||||||
@ -131,12 +152,13 @@ begin
|
|||||||
specifierIndex := paramNames.Add(name);
|
specifierIndex := paramNames.Add(name);
|
||||||
|
|
||||||
StreamWriteString(formatStream, IntToStr(specifierIndex));
|
StreamWriteString(formatStream, IntToStr(specifierIndex));
|
||||||
|
|
||||||
currentPos := nameEnd;
|
currentPos := nameEnd;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end else
|
||||||
|
|
||||||
StreamWriteChar(formatStream, currentPos^);
|
StreamWriteChar(formatStream, currentPos^);
|
||||||
|
|
||||||
Inc(currentPos);
|
Inc(currentPos);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -165,11 +187,9 @@ begin
|
|||||||
Inc(paramIndex);
|
Inc(paramIndex);
|
||||||
|
|
||||||
specifierIndex := paramNames.IndexOf(name);
|
specifierIndex := paramNames.IndexOf(name);
|
||||||
if specifierIndex = -1 then
|
if specifierIndex > -1 then
|
||||||
raise Exception.CreateFmt('Parameter "%s" could not be found in the format string',
|
|
||||||
[name]);
|
|
||||||
|
|
||||||
paramValues[specifierIndex] := AParams[paramIndex];
|
paramValues[specifierIndex] := AParams[paramIndex];
|
||||||
|
|
||||||
Inc(paramIndex);
|
Inc(paramIndex);
|
||||||
end;
|
end;
|
||||||
finally
|
finally
|
||||||
@ -180,4 +200,16 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{ TNamedFormatStringList }
|
||||||
|
procedure TNamedFormatStringList.AddLn;
|
||||||
|
begin
|
||||||
|
Add('');
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TNamedFormatStringList.Format(AParams: array of const): String;
|
||||||
|
begin
|
||||||
|
Result := NamedFormat(Text, AParams);
|
||||||
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
Loading…
Reference in New Issue
Block a user