上几篇文章中对于输出函数中的格式化字符串(format_string),索引(index)等格式化输出内容进行了详细的讲解,从这一篇开始,我们进入到一个更丰富且重要的内容:格式化说明符:[:specifier]。
格式化说明符可以更精确地将输出内容进行格式化,以:开头,其格式是这样的:
[[fill]align][sign][#][0][width][.precision][L][type]
我们比较清楚的是,在C/C++语言中,[]表示可以省略,如果不省略的话,其含义又是什么样的呢,让我们一个一个地来学习吧:
1 width宽度
width宽度指定了输出值的最小宽度,也可以用{}包住,说明是一个动态的宽度,给我们的编程带来很大的灵活性,如果将index也变成变量的话,可能就有一点复杂了,用文字描述,远没有结合程序实例更容易理解掌握,那我们就来看一个例子吧:
import std;
using namespace std;
int main()
{
int i{ 42 };
println("|{:5}|", i); // | 42|
println("|{:{}}|", i, 7); // | 42|
println("|{1:{0}}|", 7, i); // | 42|
return 0;
}
运行结果:
| 42|
| 42|
| 42|
与代码注释中一致,符合预期,我们就通过这个示例详细介绍一下width宽度的用法,||使我们更清晰地看出其输出宽度,第一个println()输出值为42,其宽度为5,最简单的那一种;第二个println(),输出值是i,为42,在外围的那对{},里面的在:后面的那对{}使用index为1的参数,其值为7,表示宽度为7,由此可以看出,如果没有标注的话,index对应的顺序是以{为准的,其输出结果与解释一致吧;从第二个println()自然而然地就能够想到,我要改变一下顺序呢,把后面的调到前面呢,第三个println()就给出了示例,不用系统默认的index,显示指出就可以了,将外围的{}调整为index为1,:后面的{},即宽度值,使用index为0,即格式化后第一个参数,就可以达到目的了。我觉得,通过实例,根据代码去理解学习width宽度值的用法,应该还是比较好懂的吧。
2 [fill]align填充对齐
align对齐是指靠左、靠右、居中,与WORD排版中的意思一致,靠左默认是针对于非数字的,靠右默认是针对于数字的;[fill]是指对于输出的空白部分的填充符,默认是空格。当然了,前提是指定了width宽度,如果没有指定宽度,这两个都不起作用。
当指定对齐方式为居中时,而需要填充的宽度为奇数时,后面多一个。
还有一个有趣的情况,就是输出填充符是我们的目的,我们就可以用““作为输出值,而在格式化字符串中的width及[fill]中给出相应的值,就可以达到我们的目的。
请看示例:
import std;
using namespace std;
int main()
{
int i{ 42 };
println("|{:7}|", i); // | 42|
println("|{:<7}|", i); // |42 |
println("|{:_<7}|", i); // |_____42|
println("|{:_^7}|", i); // |__42___|
println("|{:=>16}|", ""); //|================|
return 0;
}
看结果:
| 42|
|42 |
|42_____|
|__42___|
|================|
该结果验证了以下对于[fill]align填充对齐方式的说明,这个比上一个width宽度的使用我觉得更易于理解一些,你怎么认为呢?
3 sign符号
sign符号这个比较好理解,就是正负号的显示方式,列表如下:
- - 为缺省值,值为负数时显示-,为正数时不显示
- +值为负数时显示-,为正数时显示+
- 空格 值为负数时显示-,为正数时显示空格,这个与缺省值-在正数时显示的区别是,这个是要用空格进行占位的,而-为正数时则什么也不显示。
还是看示例吧,更好理解一些,也可以加深印象:
import std;
using namespace std;
int main()
{
int i{ 42 };
println("|{:<5}|", i); // |42 |
println("|{:<+5}|", i); // |+42 |
println("|{:< 5}|", i); // | 42 |
println("|{:< 5}|", -i); // |-42 |
return 0;
}
结果:
|42 |
|+42 |
| 42 |
|-42 |
这个比较容易理解,就直接过了,进入下一项。
4 #与type
#对于数字类型,像16进制、二进制、8进制、会在数字之前插入0x或者0X、0b或者0B、0等,对于浮点类型,会输出数字分隔符,不管后面有没有数字。
type为类型说明符,有以下几种类型,分别加以说明:
- 整型:b:二进制、B:二进制(如果指定#的话,用0B而不是0b)、d:十进制、o:八进制、x:十六进制(用a、b、c、d、e、f)、X:十六进制(用大写的A、B、C、D、E、F,如果指定#的话,用0X而不是0x)、如果没有指定类型的话,对于整型数默认为d:十进制
- 浮点类型:前面的文章已经讨论过,std::chars_format::scientific, fixed, general,以及hex,e,E:表示指数,后面跟给定精度的数字,默认为6;f,F:给定精度的固定表示,默认为6;g,G:小数点前至少有一位数字的最简洁的表达方式、a,A:十六进制中的abcdef或者ABCDEF;如果没有指定的话,就使用g,对于此处如果不好理解的话,请参见https://mp.csdn.net/mp_blog/creation/editor/140945993
- 布尔型:s:输出true或者false,b, B, c, d, o, x, X:输出0或者1,默认为s。
- 字符型:c:正常字符输出、?:转义字符输出,以后会详细讨论、b, B, d, o, x, X:整型数字输出;默认为c。
- 字符串型:s:正常字符串输出、?:转义字符串输出,以后会详细讨论,如果类型没有指定,默认为s:正常字符串输出。
- 指针型:p:以0x开头的十六进制,如果type类型没有指定的话,p就是用于指针类型,记住一点,只有void*的指针类型可以格式化输出,其他类型一定要转成void*的类型,例如:static_cast<void*>(myPointer)
先展示一下整型及字符串类型的例子,其他的,到使用的时候再展示吧:
import std;
using namespace std;
int main()
{
int i{ 42 };
println("|{:10d}|", i);
println("|{:10b}|", i);
println("|{:#10b}|", i);
println("|{:10X}|", i);
println("|{:#10X}|", i);
string s{ "ProCpp" };
println("|{:_^10}|", s);
return 0;
}
看一下结果:
| 42|
| 101010|
| 0b101010|
| 2A|
| 0X2A|
|__ProCpp__|
不多做解释了,这些都是一些死知识,理解后掌握就行了,不复杂。
5precision精度
precision精度只针对于浮点型及字符串型,格式就是小数点.后指定一个数字,对于浮点型来说,就是指定了浮点型数的位数;对于字符串型来说,就是字符串的长度。浮点型数的位数包括小数点前后的数字,但对于以f或者F表示的浮点数,指的小数点后的位数,这一点需要特别注意。
与width宽度一样,precision精度也可以使用格式化字符串后面的变量来指定,这样的话,就给程序的灵活性带来了很大的方便,精度可以使用紧挨着格式化字符串后面的变量,也可以使用index指定的格式化字符串后面的任意要输出的变量,看示例吧:
import std;
using namespace std;
int main()
{
double d{ 3.1415 / 2.3 };
println("|{:12g}|", d);
println("|{:12.2}|", d);
println("|{:12e}|", d);
int width{ 12 };
int precision{ 3 };
println("|{2:{0}.{1}f}|", width, precision, d);
println("|{2:{0}.{1}}|", width, precision, d);
return 0;
}
看结果:
| 1.36587|
| 1.4|
|1.365870e+00|
| 1.366|
| 1.37|
6 0符号
0符号比较简单,就是对于数值型的数据来说,插入0,达到指定的width宽度,0插入的位置是在数值型的数据之前,但在+、-符号、0x、0X、0b、0B等之后。当然了,如果指定了对齐方式,该符号无效,看示例:
import std;
using namespace std;
int main()
{
int i{ 42 };
println("|{:06d}|", i);
println("|{:+06d}|", i);
println("|{:06X}|", i);
println("|{:#06X}|", i);
println("|{:^06d}|", i);
return 0;
}
看结果:
|000042|
|+00042|
|00002A|
|0X002A|
| 42 |
7 L符号
L符号是本地化符号,只是针对于整型数、浮点型数、布尔型的有效,当使用L符号的时候,其输出就是当地的习惯表达;该参数只针对std::format()有效,而对于print()、println()无效。
举一个例子,设置不同的locale,看一下不同:
import std;
using namespace std;
int main()
{
float f{ 1.2f };
cout << format(std::locale{ "nl" }, "|{:Lg}|\n", f);
cout << format(std::locale{ "zh" }, "|{:Lg}|\n", f);
return 0;
}
看结果:
|1,2|
|1.2|
看,还是有与中国不同的表达方式吧,当然,我们要尊重。