我正在尝试创建一个 Rust 版本的这个问题的公认解决方案,即将“258”这样的字符串转换为 258。
我创建了下面的代码来匹配给定的伪代码,但不知何故它无法正确获取成百上千的代码。例如,我的示例字符串返回 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));
返回 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
解决此问题的简单方法是手动添加“百”
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);
}
您遇到的问题源于您的逻辑如何处理“百”和“千”的值。具体来说,在处理“一百”这个词时,它应该将当前值(例如“二”= 2)乘以 100,但您的代码过早地添加或重置值,导致结果不正确。
以下是需要调整的详细信息:
乘以刻度:遇到“百”时,应将当前值(先前值)乘以100,而不是立即重置先前值。相反,请存储此值以便使用后面的较小数字(例如“五十”和“八”)进一步计算。
累加大尺度:当遇到像“千”这样的较大尺度时,您应该在按千值缩放之前添加累加结果(例如“258”)。
纠正逻辑: 逐步处理输入字符串中的每个单词,确保遇到“百”或“千”时,在移动到下一组数字之前正确缩放当前累加值。
修复示例:修改出现“百”或“千”等比例时处理先验和结果的方式:
fn text_to_int(textnum: &str, numwords: HashMap<&str, u32>) -> u32 {
令 mut 结果 = 0; 让 mut 先验 = 0;
for word in textnum.split(" ") { 让 value = numwords[word];
if value == 100 {
prior *= value;
} else if value >= 1000 {
result += prior * value;
prior = 0;
} else {
prior += value;
}
}
结果+之前 }
说明: 仅当遇到“百”时先验才会相乘。 对于像“千”这样的大值,先验值会在缩放后添加到结果中,然后重置以进行进一步计算。 您可以进一步测试和完善此逻辑以适应更复杂的输入。如需更高级的 SEO 工具,请访问 SEO Studio Tools。