Merge pull request #3764 from cakebaker/numfmt_preserve_trailing_zeros

numfmt: preserve trailing zeros
This commit is contained in:
Sylvestre Ledru 2022-08-01 13:32:55 +02:00 committed by GitHub
commit 9b81e09f7a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 63 additions and 8 deletions

View file

@ -97,6 +97,18 @@ fn parse_suffix(s: &str) -> Result<(f64, Option<Suffix>)> {
Ok((number, suffix))
}
// Returns the implicit precision of a number, which is the count of digits after the dot. For
// example, 1.23 has an implicit precision of 2.
fn parse_implicit_precision(s: &str) -> usize {
match s.split_once('.') {
Some((_, decimal_part)) => decimal_part
.chars()
.take_while(|c| c.is_ascii_digit())
.count(),
None => 0,
}
}
fn remove_suffix(i: f64, s: Option<Suffix>, u: &Unit) -> Result<f64> {
match (s, u) {
(Some((raw_suffix, false)), &Unit::Auto) | (Some((raw_suffix, false)), &Unit::Si) => {
@ -288,11 +300,19 @@ fn format_string(
None => source,
};
let precision = if let Some(p) = options.format.precision {
p
} else if options.transform.from == Unit::None && options.transform.to == Unit::None {
parse_implicit_precision(source_without_suffix)
} else {
0
};
let number = transform_to(
transform_from(source_without_suffix, &options.transform)?,
&options.transform,
options.round,
options.format.precision,
precision,
)?;
// bring back the suffix before applying padding
@ -422,4 +442,17 @@ mod tests {
assert_eq!(0.1234, round_with_precision(0.12345, rm, 4));
assert_eq!(0.12345, round_with_precision(0.12345, rm, 5));
}
#[test]
fn test_parse_implicit_precision() {
assert_eq!(0, parse_implicit_precision(""));
assert_eq!(0, parse_implicit_precision("1"));
assert_eq!(1, parse_implicit_precision("1.2"));
assert_eq!(2, parse_implicit_precision("1.23"));
assert_eq!(3, parse_implicit_precision("1.234"));
assert_eq!(0, parse_implicit_precision("1K"));
assert_eq!(1, parse_implicit_precision("1.2K"));
assert_eq!(2, parse_implicit_precision("1.23K"));
assert_eq!(3, parse_implicit_precision("1.234K"));
}
}

View file

@ -78,7 +78,7 @@ impl RoundMethod {
pub struct FormatOptions {
pub grouping: bool,
pub padding: Option<isize>,
pub precision: usize,
pub precision: Option<usize>,
pub prefix: String,
pub suffix: String,
pub zero_padding: bool,
@ -89,7 +89,7 @@ impl Default for FormatOptions {
Self {
grouping: false,
padding: None,
precision: 0,
precision: None,
prefix: String::from(""),
suffix: String::from(""),
zero_padding: false,
@ -206,10 +206,12 @@ impl FromStr for FormatOptions {
if !precision.is_empty() {
if let Ok(p) = precision.parse() {
options.precision = p;
options.precision = Some(p);
} else {
return Err(format!("invalid precision in format '{}'", s));
}
} else {
options.precision = Some(0);
}
}
@ -302,10 +304,10 @@ mod tests {
fn test_parse_format_with_precision() {
let mut expected_options = FormatOptions::default();
let formats = vec![
("%6.2f", Some(6), 2),
("%6.f", Some(6), 0),
("%.2f", None, 2),
("%.f", None, 0),
("%6.2f", Some(6), Some(2)),
("%6.f", Some(6), Some(0)),
("%.2f", None, Some(2)),
("%.f", None, Some(0)),
];
for (format, expected_padding, expected_precision) in formats {

View file

@ -10,6 +10,14 @@ fn test_should_not_round_floats() {
.stdout_is("0.99\n1.01\n1.1\n1.22\n0.1\n-0.1\n");
}
#[test]
fn test_should_preserve_trailing_zeros() {
new_ucmd!()
.args(&["0.1000", "10.00"])
.succeeds()
.stdout_is("0.1000\n10.00\n");
}
#[test]
fn test_from_si() {
new_ucmd!()
@ -823,6 +831,18 @@ fn test_format_with_precision_and_to_arg() {
}
}
#[test]
fn test_format_preserve_trailing_zeros_if_no_precision_is_specified() {
let values = vec!["10.0", "0.0100"];
for value in values {
new_ucmd!()
.args(&["--format=%f", value])
.succeeds()
.stdout_is(format!("{}\n", value));
}
}
#[test]
fn test_format_without_percentage_directive() {
let invalid_formats = vec!["", "hello"];