有没有办法格式化输出的字符串? 我正在尝试获得以下输出的漂亮视图
1: Ashley | 01033438392 | Wellington, New Zealand | 1987- 4-14
2: Aloha | 01087651234 | Hawaii, United States of America | 1988- 9-23
3: Jack | 01082840184 | Beijing, China | 1989- 6-19
如果我用C语言编程,我会做类似的事情
printf("%10s | %11s | %20s | %4d-%2d-%2d\n",name,phone,address,year,month,day);
在Ada 05中可以进行这种格式化吗?
PS请忽略姓名,电话号码,地址和生日。我在30秒内完成了它们......
答案 0 :(得分:8)
可以这样做,但机制有点麻烦,而且相当冗长 我通常会做的是编写单独的程序来处理更复杂的输出,例如:为清晰起见,将日期与其余的字符串处理结合使用。
package Integer_IO is new Ada.Text_IO.Integer_IO (Integer);
procedure Output_Date ( Day : in Integer; Month: in Integer; Year: in Integer) is
begin
Integer_IO.Put(Item => Day, Width => 2);
Text_IO.Put("-");
Integer_IO.Put(Item => Month, Width => 2);
Text_IO.Put("-");
Integer_IO.Put(Item => Year, Width => 4);
end Output_Date;
procedure Output_String ( Item : in String;
Width : in Integer;
Separator : in String := "|";
Truncate : Boolean := False) is
Field_Index : Integer := Text_IO.Col;
begin
if Item'length > Width and Truncate then
Text_IO.Put(Item(1..Width) & Separator);
else
Text_IO.Put(Item) & Separator;
end if;
Text_IO.Set_Col ( Field_Index + Width + 1 );
end Output_String;
这将强制执行固定长度字段,这可选择允许截断长字符串,或者将后续条目移动到下一行。 Set_Col将设置下一次写入的行位置,如果当前写入位置已超过请求的位置,则可能将其置于下一行。
我把字符串截断作为一个机会使用数组切片和Text_IO的输出操作,但我通常不是默认截断的粉丝,因为允许字符串超出请求的宽度或下一行的缩进倾向于make格式错误更明显。
因此,根据上面的代码,打印出类似第一行的内容可能类似于:
Name : String := "Ashley"
Phone : String := "01033438392"
Address: String := "Wellington, New Zealand"
Day : Integer := 14;
Month : Integer := 4;
Year : Integer := 1987;
Output_String(Item=> Name, Width => 10);
Output_String(Item=> Phone, Width => 11);
Output_String(Item=> Address, Width => 20);
Output_Date(Day,Month,Year);
Ada中的文本IO通常很麻烦,但通常具有使您正在做的事情相对清晰的优点。
答案 1 :(得分:4)
请注意,在C ++中,这些天printf()
即将被折旧,转而使用带有流格式化程序的流。这是方便的,但是大规模不安全(至少在几个意义上)。现在,鼓励开发人员使用C ++流(使用各种操纵器)。
在Ada中,您可以使用字符串catenation运算符&
以与C ++流非常相似的方式处理字符串,其中C ++伙伴使用流插入运算符(<<
)。在某些方面,Ada的方法更好,因为您可以嵌套链接表达式,而不能使用插入流的表达式。
这里的问题是,setfill()
,hex
和setw()
等C ++格式化程序没有任何便利的等价物。真的应该是,并且(hex
例外)他们不难写自己,但现在他们不存在。
例如,setw()/setfill()
等价物将类似于:
Fill_Char : Character := ' ';
function Set_Fill (New_Fill : Character) return String is
begin
Fill_Char := New_Fill;
return "";
end Set_Fill;
--// Dumb tail-recursive implementation.
function Set_Width(Source : in String; Width : in Positive) return String is
begin
if Width <= Source'length then --'
return Source;
else
return Fill_Char & Set_Width(Source, Width - 1);
end if;
end Set_Width;
Unfilled_String : constant String := "123456";
Filled_String : constant String := Set_Width(Unfilled_String & Set_Fill('0'), 8);
--// The above string should end up being "00123456"
如果你真的想要一个printf()
界面,那么{A}当然可以从Ada调用printf()
。你必须担心在Ada的大小字符串和C的nul终止字符串之间转换,但这就是Ada.Interfaces.C.Strings
的用途。
答案 2 :(得分:3)
是的。虽然它不像c中那么容易。
查看§A.4.4 Bounded-Length String Handling有关如何创建预定义大小的字符串,并使用integer'image转换数字。 &amp;运算符可用于使用ada.text_io.put_line()连接字符串和输出。
答案 3 :(得分:2)
您可能会喜欢这个简单的card game simulation使用Ada.Strings.Fixed
格式化ASCII图表的范围轴标签。请参阅function Label
,该Tail
使用Trim
和Integer'Image
格式化Lower
和Upper
值的function Label (J : Integer) return String is
use Ada.Strings; use Ada.Strings.Fixed;
Lower : String := Integer'Image(J * Bin_Size);
Upper : String := Integer'Image((J + 1) * Bin_Size);
begin
return Tail(Trim(Lower, Left), 4, '0') & "-" &
Tail(Trim(Upper, Left), 4, '0') & " |*";
end Label;
。
代码:
Distribution of lengths:
0000-0100 |**********
0100-0200 |*****************************
0200-0300 |**********************
0300-0400 |***************
0400-0500 |**********
0500-0600 |*******
0600-0700 |****
0700-0800 |****
0800-0900 |**
0900-1000 |**
1000-1100 |*
1100-1200 |*
控制台:
{{1}}
答案 4 :(得分:2)
此特定格式设置有辅助工具。
procedure Put(Item : in Num; Width : in Field := Default_Width; Base : in Number_Base := Default_Base);
将与Item
对齐的字段放在右边,将空白字符作为填充符。其中Width
为字段宽度,Base
为10为defualt。
function Head (Source : in String; Count : in Natural; Pad : in Character := Space) return String;
function Tail (Source : in String; Count : in Natural; Pad : in Character := Space) return String;
返回格式化字符串。其中Count
是字段宽度,Pad
是字段的填充符。 Head
将字符串左对齐。 Tail
将字符串对齐。
让列宽为8个字符,并使用短划线作为填充。
Put_Line (Head ("Ashley", 8, '-'));
Put_Line (Head ("Aloha", 8, '-'));
Put_Line (Head ("Jack", 8, '-'));
Put_Line (Tail ("Ashley", 8, '-'));
Put_Line (Tail ("Aloha", 8, '-'));
Put_Line (Tail ("Jack", 8, '-'));
Ashley--
Aloha---
Jack----
--Ashley
---Aloha
----Jack
返回离散类型需要表示为文本的长度。
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Float_Text_IO; use Ada.Float_Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Strings.Fixed; use Ada.Strings.Fixed;
with Ada.Calendar; use Ada.Calendar;
procedure Test is
subtype Index is Positive range 95 .. 1223;
procedure Put_Line ( I : in out Index; Name : String; Phone : Natural; Address : String; T : in out Time ) is
begin
Put (I, Index'Width);
Put (": ");
Put (Head (Name, 10, ' '));
Put (" | ");
Put (Tail (Phone'Img (Phone'Img'First + 1 .. Phone'Img'Last), 13, '0'));
Put (" | ");
Put (Head (Address, 20, ' '));
Put (Year (T), Year_Number'Width);
Put ("-");
Put (Month (T), Month_Number'Width);
Put ("-");
Put (Day (T), Day_Number'Width);
I := Positive'Succ (I);
T := T + Duration (60 * 60 * 24 * 3);
New_Line;
end;
I : Index := Index'First;
Now : Time := Clock;
begin
Put_Line (I, "Ashley", 1033438392, "Wellington, New Zealand", Now);
Put_Line (I, "Aloha", 01087651234, "Hawaii, United States of America", Now);
Put_Line (I, "Jack", 01082840184, "Beijing, China", Now);
I := Index'Last - 3;
Put_Line (I,"Ashley", 1033438392, "Wellington, New Zealand", Now);
Put_Line (I,"Aloha", 01087651234, "Hawaii, United States of America", Now);
Put_Line (I,"Jack", 01082840184, "Beijing, China", Now);
end;
95: Ashley | 0001033438392 | Wellington, New Zeal 2015- 5- 24
96: Aloha | 0001087651234 | Hawaii, United State 2015- 5- 27
97: Jack | 0001082840184 | Beijing, China 2015- 5- 30
1220: Ashley | 0001033438392 | Wellington, New Zeal 2015- 6- 2
1221: Aloha | 0001087651234 | Hawaii, United State 2015- 6- 5
1222: Jack | 0001082840184 | Beijing, China 2015- 6- 8
我建议为电话号码创建一个类型,我不知道如果它应该是字符串或带有标题为零的数字,我猜的电话号码可以有不同的长度。
答案 5 :(得分:1)
您还可以使用GNAT.Formatted_String
包。
它至少适用于Ada 2012(无法检查它是否存在于Ada 2005中)。
它与printf的使用非常相似,但有一点点语法差异。
以下是一个简单的示例http://tpcg.io/iJwfWa:
with Ada.Text_IO; use Ada.Text_IO;
with GNAT.Formatted_String; use GNAT.Formatted_String;
procedure Hello is
formatStr : constant String := "Hello, %-5s !";
nameArray : constant array (1..3) of String (1..4) :=
(1 => "_Foo",
2 => "_Bar",
3 => "_Fuu");
gnatFormat : Formatted_String := +(formatStr); -- initialisation needed
begin
for index in nameArray'range loop
gnatFormat := +(formatStr); --reaffectation needed
Put_Line(-(gnatFormat & nameArray(index)));
end loop;
end Hello;
输出:
(GNATMAKE v7.1.1 on https://www.tutorialspoint.com/compile_ada_online.php)
$gnatmake -o hello *.adb
gcc -c hello.adb
gnatbind -x hello.ali
gnatlink hello.ali -o hello
$hello
Hello, _Foo !
Hello, _Bar !
Hello, _Fuu !
输入http://tpcg.io/iJwfWa的另一个例子:
with Ada.Text_IO; use Ada.Text_IO;
with GNAT.Formatted_String; use GNAT.Formatted_String;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
procedure Hello is
formatStr : constant String := "%-10s | %11d | %35s | %4d-%2d-%2d";
type T_element_descriptor is record
name : Unbounded_String;
number : Integer;
city : Unbounded_String;
birth_y : Integer; -- should use a date object ...
birth_m : Integer;
birth_d : Integer;
end record;
elementArray : constant array (1..3) of T_element_descriptor :=
(1 => (To_Unbounded_String("Ashley"), 01033438392, To_Unbounded_String("Wellington, New Zealand"), 1987, 4, 14),
2 => (To_Unbounded_String("Aloha"), 01087651234, To_Unbounded_String("Hawaii, United States of America"), 1988, 9, 23),
3 => (To_Unbounded_String("Jack"), 01082840184, To_Unbounded_String("Beijing, China"), 1989, 6, 19));
gnatFormat : Formatted_String := +formatStr;
begin
for index in elementArray'range loop
gnatFormat := +(formatStr);
Put_Line(-(gnatFormat
& To_String(elementArray(index).name)
& elementArray(index).number
& To_String(elementArray(index).city)
& elementArray(index).birth_y
& elementArray(index).birth_m
& elementArray(index).birth_d
));
end loop;
end Hello;
输出:
(GNATMAKE v7.1.1 on https://www.tutorialspoint.com/compile_ada_online.php)
$gnatmake -o hello *.adb
gcc -c hello.adb
gnatbind -x hello.ali
gnatlink hello.ali -o hello
$hello
Ashley | 1033438392 | Wellington, New Zealand | 1987- 4-14
Aloha | 1087651234 | Hawaii, United States of America | 1988- 9-23
Jack | 1082840184 | Beijing, China | 1989- 6-19
gnat提供的g-forstr.ads
文件中提供了最佳示例:
-- This package add support for formatted string as supported by C printf()
-- A simple usage is:
--
-- Put_Line (-(+"%s" & "a string"));
--
-- or with a constant for the format:
--
-- declare
-- Format : constant Formatted_String := +"%s";
-- begin
-- Put_Line (-(Format & "a string"));
-- end;
--
-- Finally a more complex example:
--
-- declare
-- F : Formatted_String := +"['%c' ; %10d]";
-- C : Character := 'v';
-- I : Integer := 98;
-- begin
-- F := F & C & I;
-- Put_Line (-F);
-- end;
-- Which will display:
-- ['v' ; 98]
-- Each format specifier is: %[flags][width][.precision][length]specifier
-- Specifiers:
-- d or i Signed decimal integer
-- u Unsigned decimal integer
-- o Unsigned octal
-- x Unsigned hexadecimal integer
-- X Unsigned hexadecimal integer (uppercase)
-- f Decimal floating point, lowercase
-- F Decimal floating point, uppercase
-- e Scientific notation (mantissa/exponent), lowercase
-- E Scientific notation (mantissa/exponent), uppercase
-- g Use the shortest representation: %e or %f
-- G Use the shortest representation: %E or %F
-- c Character
-- s String of characters
-- p Pointer address
-- % A % followed by another % character will write a single %
-- Flags:
-- - Left-justify within the given field width;
-- Right justification is the default.
-- + Forces to preceed the result with a plus or minus sign (+ or -)
-- even for positive numbers. By default, only negative numbers
-- are preceded with a - sign.
-- (space) If no sign is going to be written, a blank space is inserted
-- before the value.
-- # Used with o, x or X specifiers the value is preceeded with
-- 0, 0x or 0X respectively for values different than zero.
-- Used with a, A, e, E, f, F, g or G it forces the written
-- output to contain a decimal point even if no more digits
-- follow. By default, if no digits follow, no decimal point is
-- written.
-- ~ As above, but using Ada style based <base>#<number>#
-- 0 Left-pads the number with zeroes (0) instead of spaces when
-- padding is specified.
-- Width:
-- number Minimum number of characters to be printed. If the value to
-- be printed is shorter than this number, the result is padded
-- with blank spaces. The value is not truncated even if the
-- result is larger.
-- * The width is not specified in the format string, but as an
-- additional integer value argument preceding the argument that
-- has to be formatted.
-- Precision:
-- number For integer specifiers (d, i, o, u, x, X): precision specifies
-- the minimum number of digits to be written. If the value to be
-- written is shorter than this number, the result is padded with
-- leading zeros. The value is not truncated even if the result
-- is longer. A precision of 0 means that no character is written
-- for the value 0.
-- For e, E, f and F specifiers: this is the number of digits to
-- be printed after the decimal point (by default, this is 6).
-- For g and G specifiers: This is the maximum number of
-- significant digits to be printed.
-- For s: this is the maximum number of characters to be printed.
-- By default all characters are printed until the ending null
-- character is encountered.
-- If the period is specified without an explicit value for
-- precision, 0 is assumed.
-- .* The precision is not specified in the format string, but as an
-- additional integer value argument preceding the argument that
-- has to be formatted.