使用writeln
我可以将数字格式化为一行文字。
var
file: text;
mystring: string;
begin
writeln(file,'Result is: ', var1:8:2,' | ', var2:8:2,' |');
end;
在Delphi中是否有一个类似的易于使用的程序可以执行类似的结果
_format_string(mystring, 'Result is: ', var1:8:2,' | ', var2:8:2,' |');
谢谢。
答案 0 :(得分:16)
您使用Format
功能:
mystring := Format('The image dimensions are %d × %d.', [640, 480]);
答案 1 :(得分:12)
技术上答案是"是"。但不建议这样做。
您可以根据text file device driver类型编写自己的System.TTextRec。
我在过去(特别是在Turbo Pascal时代)已经完成了这项工作以进行调试。这是一项很多工作,需要您编写一个特殊的MyAssign
过程,并确保使用Text
块中的TTextRec
关闭try..finally
文件。繁琐,但可行。
更容易的选择是using the Format function as described by Andreas Rejbrand。
使用Format
的一个很酷的事情是,您使用Format Strings不仅可以在width
内参数化precision
和Format String
等内容,还可以像你这样的参数通常会提供价值。
您可以非常接近使用width
的8和precision
的2,就像问题中的示例一样。
例如,引用文档:
Format ('%*.*f', [8, 2, 123.456]);
相当于:
Format ('%8.2f', [123.456]);
Format
和Format Strings
这是一个被忽视的功能。
答案 2 :(得分:6)
虽然Jeroen不推荐它,但大约一年前我做过这样的事情 - 只是为了学习如何做到这一点。这是代码:
type
TTextFile = class
private type
TTextRecHelper = record helper for TTextRec
public
function GetTextFile: TTextFile;
procedure SetTextFile(const Value: TTextFile);
property TextFile: TTextFile read GetTextFile write SetTextFile;
end;
private var
FBuilder: TStringBuilder;
class function TextClose(var F: TTextRec): Integer; static;
class function TextIgnore(var F: TTextRec): Integer; static;
class function TextInput(var F: TTextRec): Integer; static;
class function TextOpen(var F: TTextRec): Integer; static;
class function TextOutput(var F: TTextRec): Integer; static;
procedure AppendString(const Value: string);
procedure AssignFile(var F: Text);
public
var F: Text;
constructor Create;
destructor Destroy; override;
function ToString: string; override;
end;
constructor TTextFile.Create;
begin
inherited Create;
FBuilder := TStringBuilder.Create();
AssignFile(F);
Rewrite(F);
end;
destructor TTextFile.Destroy;
begin
Close(F);
FBuilder.Free;
inherited Destroy;
end;
procedure TTextFile.AppendString(const Value: string);
begin
FBuilder.Append(Value);
end;
procedure TTextFile.AssignFile(var F: Text);
begin
FillChar(F, SizeOf(F), 0);
with TTextRec(F)do
begin
Mode := fmClosed;
BufSize := SizeOf(Buffer);
BufPtr := @Buffer;
OpenFunc := @TextOpen;
TextFile := Self;
end;
end;
class function TTextFile.TextClose(var F: TTextRec): Integer;
begin
Result := 0;
end;
class function TTextFile.TextIgnore(var F: TTextRec): Integer;
begin
Result := 0;
end;
class function TTextFile.TextInput(var F: TTextRec): Integer;
begin
F.BufPos := 0;
F.BufEnd := 0;
Result := 0;
end;
class function TTextFile.TextOpen(var F: TTextRec): Integer;
begin
if F.Mode = fmInput then
begin
F.InOutFunc := @TextInput;
F.FlushFunc := @TextIgnore;
F.CloseFunc := @TextIgnore;
end else
begin
F.Mode := fmOutput;
F.InOutFunc := @TextOutput;
F.FlushFunc := @TextOutput;
F.CloseFunc := @TextClose;
end;
Result := 0;
end;
class function TTextFile.TextOutput(var F: TTextRec): Integer;
var
AStr: AnsiString;
begin
SetLength(AStr, F.BufPos);
Move(F.BufPtr^, AStr[1], F.BufPos);
F.TextFile.AppendString(string(AStr));
F.BufPos := 0;
Result := 0;
end;
function TTextFile.ToString: string;
begin
Close(F);
result := FBuilder.ToString;
Rewrite(F);
end;
function TTextFile.TTextRecHelper.GetTextFile: TTextFile;
begin
Move(UserData[1], Result, Sizeof(Result));
end;
procedure TTextFile.TTextRecHelper.SetTextFile(const Value: TTextFile);
begin
Move(Value, UserData[1], Sizeof(Value));
end;
根据您的问题如何使用它的示例:
tf := TTextFile.Create;
try
Writeln(tf.F, 'Result is: ', var1:8:2,' | ', var2:8:2,' |');
Caption := tf.ToString;
finally
tf.Free;
end;
答案 3 :(得分:2)
Writeln(file, 'Result is: ', var1:8:2,' | ', var2:8:2,' |');
输出:
Result is: 4.50 | 0.67 |
似乎Delphi在没有尊重DecimalSeparator的情况下进行旧的Pascal格式化。这就是为什么Writeln
输出使用.
以及下面的其他方法使用,
(我是Spanish版本的Windows)的原因。
在现代Delphi版本中,TStringBuilder为字符串连接提供了一种优雅的方式,支持fluent interfaces。它具有有限的格式化功能,但包含Format
风格(作为常规Format
函数,它非常有用,但缺少类型检查):
sb := TStringBuilder.Create;
try
sb.Append('Result is: ').Append(var1).Append(' | ').Append(var2).Append(' |');
Memo.Lines.Add(sb.ToString);
sb.Clear;
sb.AppendFormat('Result is: %8.2f | %8.2f |', [var1, var2]);
Memo.Lines.Add(sb.ToString);
finally
sb.Free;
end;
输出:
Result is: 4,5 | 0,666666666666667 |
Result is: 4,50 | 0,67 |
使用一些技巧,例如运算符重载和closures,可以模仿 C ++ ostream insertion operator:
Memo.Lines.Add(stringout < 'My ' < 5 < ' cents' < soEndl < '2/3: ' < soPrec(4) < 2/3);
输出:
My 5 cents
2/3: 0,6667
你的例子:
Memo.Lines.Add(
stringout
< 'Result is: ' < soWidth(8) < soPrec(2) < var1 < ' | '
< soWidth(8) < soPrec(2) < var2 < ' |'
);
输出:
Result is: 4,50 | 0,67 |
当Delphi支持类中的运算符重载时,实现会更加清晰。同时,使用记录进行操作符重载和接口进行自动内存管理可以解决问题:
type
PStringOut = ^TStringOut;
TStringOutManipulatorRef = reference to procedure(pso: PStringOut);
PStringOutInternalStorage = ^TStringOutInternalStorage;
TStringOutInternalStorage = record
Data: TStringBuilder;
Width, Precision: integer;
procedure ClearFormat; inline;
function GetFormatString(formatType: char): string;
end;
IStringOutInternal = interface
function TheStorage: PStringOutInternalStorage;
end;
TStringOutInternal = class(TInterfacedObject, IStringOutInternal)
strict private
Storage: TStringOutInternalStorage;
private
constructor Create;
function TheStorage: PStringOutInternalStorage;
public
destructor Destroy; override;
end;
TStringOut = record
private
Buffer: IStringOutInternal;
public
// insertion operator
class operator LessThan(const this: TStringOut; add: string): TStringOut;
class operator LessThan(const this: TStringOut; add: char): TStringOut;
class operator LessThan(const this: TStringOut; add: integer): TStringOut;
class operator LessThan(const this: TStringOut; add: double): TStringOut;
class operator LessThan(const this: TStringOut; manipulator: TStringOutManipulatorRef): TStringOut; inline;
// implicit conversion to string ("extraction" operator)
class operator Implicit(const this: TStringOut): string; inline;
end;
{ TStringOutInternalStorage }
procedure TStringOutInternalStorage.ClearFormat;
begin
Width := 0;
Precision := 0;
end;
function TStringOutInternalStorage.GetFormatString(formatType: char): string;
begin
Result := '%';
if Width > 0 then
Result := Result + IntToStr(Width);
if Precision > 0 then
Result := Result + '.' + IntToStr(Precision);
Result := Result + formatType;
end;
{ TStringOutInternal }
constructor TStringOutInternal.Create;
begin
inherited;
Storage.Data := TStringBuilder.Create;
end;
destructor TStringOutInternal.Destroy;
begin
Storage.Data.Free;
inherited;
end;
function TStringOutInternal.TheStorage: PStringOutInternalStorage;
begin
Result := @Storage;
end;
{ TStringOut }
class operator TStringOut.Implicit(const this: TStringOut): string;
begin
Result := this.Buffer.TheStorage.Data.ToString;
end;
class operator TStringOut.LessThan(const this: TStringOut; add: string): TStringOut;
begin
this.Buffer.TheStorage.Data.AppendFormat(this.Buffer.TheStorage.GetFormatString('s'), [add]);
this.Buffer.TheStorage.ClearFormat;
Result.Buffer := this.Buffer;
end;
class operator TStringOut.LessThan(const this: TStringOut; add: char): TStringOut;
begin
this.Buffer.TheStorage.Data.Append(add);
this.Buffer.TheStorage.ClearFormat;
Result.Buffer := this.Buffer;
end;
class operator TStringOut.LessThan(const this: TStringOut; add: integer): TStringOut;
begin
this.Buffer.TheStorage.Data.AppendFormat(this.Buffer.TheStorage.GetFormatString('d'), [add]);
this.Buffer.TheStorage.ClearFormat;
Result.Buffer := this.Buffer;
end;
class operator TStringOut.LessThan(const this: TStringOut; add: double): TStringOut;
var
s: PStringOutInternalStorage;
begin
s := this.Buffer.TheStorage;
if s.Precision <> 0
then s.Data.AppendFormat(s.GetFormatString('f'), [add])
else s.Data.AppendFormat(s.GetFormatString('g'), [add]);
s.ClearFormat;
Result.Buffer := this.Buffer;
end;
class operator TStringOut.LessThan(const this: TStringOut; manipulator: TStringOutManipulatorRef): TStringOut;
begin
Result := this;
manipulator(@Result);
end;
{ Manipulators }
function soEndl: TStringOutManipulatorRef;
begin
Result :=
procedure(pso: PStringOut)
begin
pso.Buffer.TheStorage.Data.AppendLine;
pso.Buffer.TheStorage.ClearFormat;
end;
end;
function soWidth(value: integer): TStringOutManipulatorRef;
begin
Result :=
procedure(pso: PStringOut)
begin
pso.Buffer.TheStorage.Width := value;
end;
end;
function soPrec(value: integer): TStringOutManipulatorRef;
begin
Result :=
procedure(pso: PStringOut)
begin
pso.Buffer.TheStorage.Precision := value;
end;
end;
{ The stringout "constructor" }
function stringout: TStringOut; inline;
begin
Result.Buffer := TStringOutInternal.Create;
end;