是否可以在Rust中打印一个用千位分隔符格式化的数字?

时间:2014-11-18 15:56:45

标签: rust

例如

println!("{}", 10_000_000);

结果

10000000

而我想将其格式化为类似

10,000,000

我经历了the fmt module documentation,但没有什么可以涵盖这种特殊情况。我觉得这样的事情会起作用

println!("{:,i}", 10_000_000);

但它会抛出错误

invalid format string: expected `}`, found `,`

7 个答案:

答案 0 :(得分:5)

没有,可能不会。

根据您所处的位置,千位分隔符也可以像1,00,00,0001.000.000,000或其他变种一样工作。

本地化不是stdlib的工作,加上format!主要是在编译时处理的(虽然公平地说这可以很容易地放在它的运行时部分),而且你不需要想要将一个语言环境硬化到程序中。

答案 1 :(得分:2)

num_format crate将为您解决此问题。添加您的语言环境,它将神奇。

答案 2 :(得分:1)

另一种解决方法是使用separator crate在float,integer和size类型上实现.separated_string()方法。这是一个例子:

extern crate separator;
use separator::Separatable;

fn main() {
    let x1: u16 = 12345;
    let x2: u64 = 4242424242;
    let x3: u64 = 232323232323;
    println!("Unsigned ints:\n{:>20}\n{:>20}\n{:>20}\n", x1.separated_string(), x2.separated_string(), x3.separated_string());

    let x1: i16 = -12345;
    let x2: i64 = -4242424242;
    let x3: i64 = -232323232323;
    println!("Signed ints:\n{:>20}\n{:>20}\n{:>20}\n", x1.separated_string(), x2.separated_string(), x3.separated_string());


    let x1: f32 = -424242.4242;
    let x2: f64 = 23232323.2323;
    println!("Floats:\n{:>20}\n{:>20}\n", x1.separated_string(), x2.separated_string());


    let x1: usize = 424242;
    // let x2: isize = -2323232323;  // Even though the docs say so, the traits seem not to be implemented for isize
    println!("Size types:\n{:>20}\n", x1.separated_string());        
}

它为您提供以下输出:

Unsigned ints:
              12,345
       4,242,424,242
     232,323,232,323

Signed ints:
             -12,345
      -4,242,424,242
    -232,323,232,323

Floats:
         -424,242.44
     23,232,323.2323

Size types:
             424,242

请注意,对齐这样的浮点数并不容易,因为separated_string()会返回一个字符串。但是,这是一种相对快速的方法来获取分开的数字。

答案 3 :(得分:0)

关于自定义功能,我玩弄了这个,这里有一些想法:

use std::str;

fn main() {
    let i = 10_000_000i;
    println!("{}", decimal_mark1(i.to_string()));
    println!("{}", decimal_mark2(i.to_string()));
    println!("{}", decimal_mark3(i.to_string()));
}

fn decimal_mark1(s: String) -> String {
    let bytes: Vec<_> = s.bytes().rev().collect();
    let chunks: Vec<_> = bytes.chunks(3).map(|chunk| str::from_utf8(chunk).unwrap()).collect();
    let result: Vec<_> = chunks.connect(" ").bytes().rev().collect();
    String::from_utf8(result).unwrap()
}

fn decimal_mark2(s: String) -> String {
    let mut result = String::with_capacity(s.len() + ((s.len() - 1) / 3));
    let mut i = s.len();
    for c in s.chars() {
        result.push(c);
        i -= 1;
        if i > 0 && i % 3 == 0 {
            result.push(' ');
        }
    }
    result
}

fn decimal_mark3(s: String) -> String {
    let mut result = String::with_capacity(s.len() + ((s.len() - 1) / 3));
    let first = s.len() % 3;
    result.push_str(s.slice_to(first));
    for chunk in s.slice_from(first).as_bytes().chunks(3) {
        if !result.is_empty() {
            result.push(' ');
        }
        result.push_str(str::from_utf8(chunk).unwrap());
    }
    result
}

围栏:http://is.gd/UigzCf

欢迎评论,他们都没有感觉真的很好。

答案 4 :(得分:0)

这是整数的幼稚实现

fn pretty_print_int(i: isize) {
    let mut s = String::new();
    let i_str = i.to_string();
    let a = i_str.chars().rev().enumerate();
    for (idx, val) in a {
        if idx != 0 && idx % 3 == 0 {
            s.insert(0, ',');
        }
        s.insert(0, val);
    }
    println!("{}", s);
}

pretty_print_int(10_000_000);
// 10,000,000

如果您想使它更通用一些整数,可以使用num::Integer特征

extern crate num;

use num::Integer;

fn pretty_print_int<T: Integer>(i: T) {
    ...
}

答案 5 :(得分:0)

用千位分隔符格式化数字的最简单方法——但没有区域设置
使用 thousands 板条箱

use thousands::Separable;

println!("{}", 10_000_000.separate_with_commas());

答案 6 :(得分:-1)

如果您不立即需要字符串,并且可能需要变量分组,您可能需要考虑基于迭代器的方法。

fn thsep(digits: &str, n: usize) -> impl Iterator<Item = &str> {
    let (chars, tip) = (digits.as_bytes(), digits.len() % n);
    if tip != 0 { Some(&chars[..tip]) } else { None }
        .into_iter()
        .chain(chars[tip..].chunks(n))
        .map(|digits| {
            std::str::from_utf8(digits).expect("unexpected non-utf8 char encountered")
        })
}

fn join(i: impl Iterator<Item = &'static str>) -> String {
    i.collect::<Vec<_>>().join(",")
}

fn main() {
    let val = "1234567890";
    println!("{}", join(thsep(val, 1))); // 1,2,3,4,5,6,7,8,9,0
    println!("{}", join(thsep(val, 2))); // 12,34,56,78,90
    println!("{}", join(thsep(val, 3))); // 1,234,567,890 • 3
    println!("{}", join(thsep(val, 4))); // 12,3456,7890
}