3个版本
0.1.2 | 2021年2月24日 |
---|---|
0.1.1 | 2021年2月23日 |
0.1.0 | 2021年2月23日 |
338 in 数学
108 每月下载次数
用于 calc
64KB
965 行
num-runtime-fmt
根据运行时规格格式化数字。
为什么还需要另一个数值格式化库?
此库通过结合其他地方找不到的特性实现了数值格式化。
- 运行时:格式说明符不需要事先知道
- 灵活:格式说明符支持标准库中几乎所有的特性。
- 专注:提供非常简单的接口,一次只能格式化一个数字。更复杂的格式化任务可以通过将输出传递到标准格式化机制来完成。
替代方案
std::fmt
表达能力强且内置在标准库中。然而,您必须在编译时提供格式字符串,并且它无法处理数字分隔。num-format
比较全面,支持no-std
应用程序。然而,它不支持非十进制输出模式或任意分组。runtime-fmt
允许使用运行时格式字符串,它支持标准库所做的一切,但仅限于nightly版本。fomat-macros
提供了具有自己语法的替代格式化宏,但似乎比stdlib中的宏功能弱。
格式字符串参考
本包中的格式化程序实现了与标准库中提供的格式宏提供的功能几乎相同的子集。然而,它们仅专注于格式化单个数值。因此,规范语言有所简化:省略了花括号以及格式规范之前的冒号。因此,在标准格式化机制中,您可能会编写
let hex_digit = format!("{:02x}", 0xf0);
使用此库,等效的写法将是
let hex_digit = NumFmt::from_str("02x")?.fmt(0xf0);
注意:虽然这些格式化程序支持标准格式化程序的子集功能,并且在此库中,使用标准格式化程序可以实现的所有功能都可以使用此库实现,但它们的语法并不包含所有标准格式化程序的语法:交集很大,但有一些在标准格式化程序中合法而在此格式化程序中不合法的语法元素。特别是,标准格式化程序支持命名的宽度参数。此包中允许动态宽度参数,但不能命名。
语法
格式字符串的语法在很大程度上借鉴了标准库的
format_spec := [[fill]align][sign]['#'][['0']width]['.' precision][format][separator[spacing]]
fill := character
align := '<' | '^' | '>' | 'v'
sign := '+' | '-'
width := integer not beginning with '0'
precision := integer
format := 'b' | 'o' | 'd' | 'x' | 'X'
separator := '_', | ',' | ' '
spacing := integer
注意:没有特殊的语法来动态插入
with
、precision
和spacing
。只需使用NumFmt::format_with
;那里的动态值始终覆盖格式字符串中设置的任何值,无论这些值是已设置还是未设置。
填充
任何在对齐指定符之前出现的单个 char
被视为填充字符:当 width
大于数字的实际渲染宽度时,超出部分将使用此字符进行填充。
注意:宽字符按其位宽计算,而不是数量。
let heart = '🖤';
assert_eq!(heart.len_utf8(), 4);
let fmt = NumFmt::builder().fill(heart).width(6).build();
// Note that this renders as two characters: we requested a width of 6.
// The number renders as a single character. The heart fills up the next 4 for a total of 5.
// Adding an extra heart would exceed the requested width, so it only renders one.
assert_eq!(fmt.fmt(1), "🖤1");
align
ment
>
:输出在width
列宽中右对齐(默认)。^
:输出在width
列宽中居中。<
:输出在width
列宽中左对齐。v
:尝试将小数点对齐到列索引width
。对于整数,等同于>
。
符号
-
:对于负数打印前导-
,对于正数则不打印任何特殊字符(默认)+
:对于正数打印前导+
#
如果存在一个 #
字符,则根据其格式在数字之前打印基数规范(参见下面的 format
)。
- 二进制:
0b
- 八进制:
0o
- 十进制:
0d
- 十六进制:
0x
此基数规范计入数字的宽度
assert_eq!(NumFmt::from_str("#04b").unwrap().fmt(2), "0b10");
0
启用零处理程序。
零处理程序覆盖填充规范为 0
,并将填充字符视为数字的一部分,与默认行为不同,默认行为将它们视为任意间隔。
示例
// sign handling
assert_eq!(NumFmt::from_str("-03").unwrap().fmt(-1).unwrap(), "-01");
assert_eq!(NumFmt::from_str("0>-3").unwrap().fmt(-1).unwrap(), "-001");
// separator handling
assert_eq!(NumFmt::from_str("0>7,").fmt(1).unwrap(), "0000001");
assert_eq!(NumFmt::from_str("07,").fmt(1).unwrap(), "000,001");
宽度
这是格式应占据的“最小宽度”参数。如果值的字符串不足以填充这么多字符,则将使用填充/对齐指定的填充来填充所需的空间(参见上面的 fill
)。
当使用 $
符号而不是显式宽度时,宽度可以动态设置
assert_eq!(NumFmt::from_str("-^$").unwrap().fmt_with(1, Dynamic::width(5)), "--1--");
如果没有提供显式宽度,则默认为 0。
精度
打印的小数点后有多少位数字。注意,可以使用此修饰符强制整数输出小数位数。
如果没有提供显式精度,则默认输出底层类型输出的所有小数位数。
assert_eq!(NumFmt::from_str(".2").unwrap().fmt(3.14159).unwrap(), "3.14");
assert_eq!(NumFmt::from_str(".7").unwrap().fmt(3.14159).unwrap(), "3.1415900");
如果请求的精度超过了此数字可用的本地精度,则余数始终用 '0'
填充,即使指定了 fill
assert_eq!(NumFmt::from_str("-<6.2").unwrap().fmt(1.0_f32).unwrap(), "1.00--");
格式
b
:输出此数字的二进制表示形式o
:输出此数字的八进制表示形式d
:输出此数字的十进制表示形式(默认)x
:输出此数字的小写字母十六进制表示形式X
:输出此数字的大写字母十六进制表示形式
注意:这是标准库具有而此库没有功能的一小部分地区之一:它支持一些其他数字格式。欢迎提交拉取请求以实现这一目标。
分隔符
分隔符是在数字组之间插入的(通常是非数字)字符,使人类在阅读时更容易解析数字。在不同上下文中可能需要不同的分隔符。
_
:使用下划线分隔数字组,
:使用逗号分隔数字组
默认情况下,不分隔数字组。在格式字符串中使用时,无法显式指定不分隔数字组。但是,可以通过构建器进行指定。
当使用构建器显式设置格式化程序选项时,还可以使用任意 char
来分隔数字组。这可能对例如支持德语数字格式很有用,德语数字格式使用 .
来分隔数字组,并使用 ,
作为小数分隔符。
间距
间距确定每个字符组的字符数。只有当设置了分隔符时才有意义。默认间距为3。
显然,某些文化使用非固定大小的组来分隔数字。如果此功能对您很重要,请提交问题。
小数分隔符
当使用构建器显式设置格式化程序选项时,可以将小数分隔符设置为任何 char
。这可能对例如支持德语数字格式很有用,德语数字格式使用 .
来分隔数字组,并使用 ,
作为小数分隔符。
依赖项
~2.9–4.5MB
~80K SLoC