mirror of
https://github.com/uutils/coreutils
synced 2024-12-13 14:52:41 +00:00
Merge pull request #3764 from cakebaker/numfmt_preserve_trailing_zeros
numfmt: preserve trailing zeros
This commit is contained in:
commit
9b81e09f7a
3 changed files with 63 additions and 8 deletions
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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"];
|
||||
|
|
Loading…
Reference in a new issue