文本到数字转换

Text to Number Conversion

我正在尝试创建一个 accepted solution to this question 的 Rust 版本,即将“258”等字符串转换为 258。

我创建了下面的代码来匹配给定的伪代码,但不知何故它无法得到成百上千的正确。例如,我的示例字符串 returns 158 而不是 258。我错过了什么?

let _units = vec![ "zero", "one", "two", "three", "four", "five", "six", "seven", 
  "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", 
  "sixteen", "seventeen", "eighteen", "nineteen", ];    

let mut numbers: Vec<(&str,u32)> = _units.iter().enumerate().map(|(idx, n)| (*n, idx as u32)).collect();

let _tens = vec!["", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"];

let mut tens: Vec<(&str,u32)> = _tens.iter().enumerate().map(|(idx, n)| (*n, (idx * 10) as u32)).collect();

let _scales = vec!["hundred", "thousand", "million", "billion"];

let base:i32 = 1000;

let mut scales: Vec<(&str,u32)> = _scales.iter().enumerate().map(|(idx, n)| (*n, base.pow(idx as u32) as u32)).collect();

numbers.append(&mut tens);
numbers.append(&mut scales);

use std::collections::HashMap;

fn text_to_int(textnum: &str, numwords: HashMap<&str, u32>) -> u32 {
  let mut result = 0;
  let mut prior = 0;

  for word in textnum.split(" ") {
    let value = numwords[word];

    if prior == 0 {
      prior = value;
    } else if prior > value {
      prior += value;
    } else {
      prior *= value;
    };

    if value > 100 && prior != 0 {
      result += prior;
      prior = 0;
    };
  }
  return result + prior;
}

let numwords: HashMap<_, _> = numbers.into_iter().collect();

let textnum = "two hundred fifty eight thousand";

println!("{:?}", text_to_int(textnum, numwords));

Returns 158000。我做错了什么?

你的问题出在这一行

let base:i32 = 1000;

let mut scales: Vec<(&str,u32)> = _scales.iter().enumerate().map(|(idx, n)| (*n, base.pow(idx as u32) as u32)).collect();

因为“百”给你的是 1 而不是 100

使用您的算法无法为 scales

生成正确的数字
"hundred" -> 100 -> 10^2
"thousand" -> 1_000 -> 10^3
"million" -> 1_000_000 -> 10^6
"billion" -> 1_000_000_000 -> 10^9

解决此问题的简单方法是手动添加“hundred”

let _scales = vec!["thousand", "million", "billion"];
let base:i32 = 1000;
let mut scales: Vec<(&str,u32)> = _scales.iter().enumerate().map(|(idx, n)| (*n, base.pow(idx as u32 + 1) as u32)).collect();

numbers.append(&mut tens);
numbers.append(&mut scales);
numbers.push(("hundred", 100));

[编辑] 解决这个问题的另一种方法是使用 FromStr ,这将为您提供 parse() 函数

的优势

为此,您可以使用以下代码

首先创建一个用于保存值的自定义类型,例如 u32

#[derive(Debug)]
struct Number<T>(T);

如果你也实现 Display 就好了(可选)

impl<T: Display> Display for Number<T> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.0)
    }
}

现在创建文本号码映射

const BASIC: [(&'static str, u32); 32] = [
    ("zero", 0), 
    ("one", 1), 
    ("two", 2), 
    ("three", 3), 
    ("four", 4), 
    ("five", 5), 
    ("six", 6), 
    ("seven", 7), 
    ("eight", 8), 
    ("nine", 9), 
    ("ten", 10),
    ("eleven", 11),
    ("twelve", 12),
    ("thirteen", 13),
    ("fourteen", 14),
    ("fifteen", 15), 
    ("sixteen", 16),
    ("seventeen", 17),
    ("eighteen", 18),
    ("nineteen", 19),
    ("twenty", 20),
    ("thirty", 30),
    ("forty", 40),
    ("fifty", 50),
    ("sixty", 60),
    ("seventy", 70),
    ("eighty", 80),
    ("ninety", 90),
    ("hundred", 100),
    ("thousand", 1000),
    ("million", 1000000),
    ("billion", 1000000000),
];

现在只需将您的 text_to_int 函数代码放在 FromStr 函数中,就像这样

impl FromStr for Number<u32> {
    type Err = ();

    fn from_str(textnum: &str) -> Result<Self, Self::Err> {
        let textnum = textnum.to_lowercase();
        let numwords: HashMap<_, _> = BASIC.into_iter().collect();
        let mut result = 0u32;
        let mut prior = 0u32;

        for word in textnum.split(" ") {
            let value = numwords[word].into();

            if prior == 0 {
                prior = value;
            } 
            else if prior > value {
                prior += value;
            } 
            else {
                prior *= value;
            }

            if value > 100 && prior != 0 {
                result += prior;
                prior = 0;
            }
        }
        Ok(Number(result + prior))
    }
}

现在您可以像这样解析每个 &str

fn main() {
    let num: Number<u32> = "two hundred fifty eight thousand".parse().unwrap();
    println!("{}", num);
}