mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
seq: compute width of numbers after parsing
Fix a bug in `seq` where the number of characters needed to print the number was computed incorrectly in some cases. This commit changes the computation of the width to be after parsing the number instead of before, in order to accommodate inputs like `1e3`, which requires four digits when printing the number, not three.
This commit is contained in:
parent
64a65370b0
commit
5cd55391ec
2 changed files with 78 additions and 6 deletions
|
@ -61,6 +61,38 @@ impl Number {
|
|||
Number::F64(n) => n,
|
||||
}
|
||||
}
|
||||
|
||||
/// Number of characters needed to print the integral part of the number.
|
||||
///
|
||||
/// The number of characters includes one character to represent the
|
||||
/// minus sign ("-") if this number is negative.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// use num_bigint::{BigInt, Sign};
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// Number::BigInt(BigInt::new(Sign::Plus, vec![123])).num_digits(),
|
||||
/// 3
|
||||
/// );
|
||||
/// assert_eq!(
|
||||
/// Number::BigInt(BigInt::new(Sign::Minus, vec![123])).num_digits(),
|
||||
/// 4
|
||||
/// );
|
||||
/// assert_eq!(Number::F64(123.45).num_digits(), 3);
|
||||
/// assert_eq!(Number::MinusZero.num_digits(), 2);
|
||||
/// ```
|
||||
fn num_digits(&self) -> usize {
|
||||
match self {
|
||||
Number::MinusZero => 2,
|
||||
Number::BigInt(n) => n.to_string().len(),
|
||||
Number::F64(n) => {
|
||||
let s = n.to_string();
|
||||
s.find('.').unwrap_or_else(|| s.len())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Number {
|
||||
|
@ -121,13 +153,11 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
|||
};
|
||||
|
||||
let mut largest_dec = 0;
|
||||
let mut padding = 0;
|
||||
let first = if numbers.len() > 1 {
|
||||
let slice = numbers[0];
|
||||
let len = slice.len();
|
||||
let dec = slice.find('.').unwrap_or(len);
|
||||
largest_dec = len - dec;
|
||||
padding = dec;
|
||||
crash_if_err!(1, slice.parse())
|
||||
} else {
|
||||
Number::BigInt(BigInt::one())
|
||||
|
@ -137,7 +167,6 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
|||
let len = slice.len();
|
||||
let dec = slice.find('.').unwrap_or(len);
|
||||
largest_dec = cmp::max(largest_dec, len - dec);
|
||||
padding = cmp::max(padding, dec);
|
||||
crash_if_err!(1, slice.parse())
|
||||
} else {
|
||||
Number::BigInt(BigInt::one())
|
||||
|
@ -150,15 +179,18 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
|||
);
|
||||
return 1;
|
||||
}
|
||||
let last = {
|
||||
let last: Number = {
|
||||
let slice = numbers[numbers.len() - 1];
|
||||
padding = cmp::max(padding, slice.find('.').unwrap_or_else(|| slice.len()));
|
||||
crash_if_err!(1, slice.parse())
|
||||
};
|
||||
if largest_dec > 0 {
|
||||
largest_dec -= 1;
|
||||
}
|
||||
|
||||
let padding = first
|
||||
.num_digits()
|
||||
.max(increment.num_digits())
|
||||
.max(last.num_digits());
|
||||
match (first, last, increment) {
|
||||
(Number::MinusZero, Number::BigInt(last), Number::BigInt(increment)) => print_seq_integers(
|
||||
(BigInt::zero(), increment, last),
|
||||
|
@ -298,12 +330,14 @@ fn print_seq_integers(
|
|||
if !is_first_iteration {
|
||||
print!("{}", separator);
|
||||
}
|
||||
let mut width = padding;
|
||||
if is_first_iteration && is_first_minus_zero {
|
||||
print!("-");
|
||||
width -= 1;
|
||||
}
|
||||
is_first_iteration = false;
|
||||
if pad {
|
||||
print!("{number:>0width$}", number = value, width = padding);
|
||||
print!("{number:>0width$}", number = value, width = width);
|
||||
} else {
|
||||
print!("{}", value);
|
||||
}
|
||||
|
@ -314,3 +348,23 @@ fn print_seq_integers(
|
|||
print!("{}", terminator);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::Number;
|
||||
use num_bigint::{BigInt, Sign};
|
||||
|
||||
#[test]
|
||||
fn test_number_num_digits() {
|
||||
assert_eq!(
|
||||
Number::BigInt(BigInt::new(Sign::Plus, vec![123])).num_digits(),
|
||||
3
|
||||
);
|
||||
assert_eq!(
|
||||
Number::BigInt(BigInt::new(Sign::Minus, vec![123])).num_digits(),
|
||||
4
|
||||
);
|
||||
assert_eq!(Number::F64(123.45).num_digits(), 3);
|
||||
assert_eq!(Number::MinusZero.num_digits(), 2);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -158,3 +158,21 @@ fn test_drop_negative_zero_end() {
|
|||
.stdout_is("1\n0\n")
|
||||
.no_stderr();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_width_scientific_notation() {
|
||||
new_ucmd!()
|
||||
.args(&["-w", "999", "1e3"])
|
||||
.succeeds()
|
||||
.stdout_is("0999\n1000\n")
|
||||
.no_stderr();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_width_negative_zero() {
|
||||
new_ucmd!()
|
||||
.args(&["-w", "-0", "1"])
|
||||
.succeeds()
|
||||
.stdout_is("-0\n01\n")
|
||||
.no_stderr();
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue