rust - 解析一串单字符命令的有效方法是什么,每个命令可选地后跟一个整数重复计数?
问题描述
我正在实现一个机器人,它接受像L
(左转)、R
(右转)和M
(前进)这样的命令。这些命令可以增加一个量词,例如M3LMR2
(移动 3 步,左转,移动 1 步,转脸)。这相当于MMMLMRR
.
我编写了可以理解以下枚举的机器人结构:
pub enum Message {
TurnLeft(i8),
TurnRight(i8),
MoveForward(i8),
}
Robot::execute(&mut self, orders: Vec<Message>)
正在正确地完成其工作。
现在,我正在努力为字符串解析、处理 、 和不安全切片编写一些体面的东西,&str
因为String
标记char
可以是 1 个或多个字符。
我已经尝试过正则表达式匹配(几乎成功),但我真的想标记字符串:
fn capture(orders: &String, start: &usize, end: &usize) -> Message {
unsafe {
let order = orders.get_unchecked(start..end);
// …
};
Message::TurnLeft(1) // temporary
}
pub fn parse_orders(orders: String) -> Result<Vec<Message>, String> {
let mut messages = vec![];
let mut start: usize = 0;
let mut end: usize = 0;
while end < orders.len() && end != start {
end += 1;
match orders.get(end) {
Some('0'...'9') => continue,
_ => {
messages.push(capture(&orders, &start, &end));
start = end;
}
}
}
Ok(messages)
}
这不会编译并且很笨拙。
这个想法是编写一个解析器,将订单字符串转换为 的向量Message
:
let messages = parse_order("M3LMR2");
println!("Messages => {:?}", messages);
// would print
// [Message::MoveForward(3), Message::TurnLeft(1), Message::MoveForward(1), Message::TurnRight(2)]
这样做的有效/优雅方式是什么?
解决方案
您可以使用迭代器、使用parse
和一些基本String
处理非常简单地做到这一点:
#[derive(Debug, PartialEq, Clone)]
enum Message {
TurnLeft(u8),
TurnRight(u8),
MoveForward(u8),
}
struct RobotOrders(String);
impl RobotOrders {
fn new(source: impl Into<String>) -> Self {
RobotOrders(source.into())
}
}
impl Iterator for RobotOrders {
type Item = Message;
fn next(&mut self) -> Option<Message> {
self.0.chars().next()?;
let order = self.0.remove(0);
let n_digits = self.0.chars().take_while(char::is_ascii_digit).count();
let mut number = self.0.clone();
self.0 = number.split_off(n_digits);
let number = number.parse().unwrap_or(1);
Some(match order {
'L' => Message::TurnLeft(number),
'R' => Message::TurnRight(number),
'M' => Message::MoveForward(number),
_ => unimplemented!(),
})
}
}
fn main() {
use Message::*;
let orders = RobotOrders::new("M3LMR2");
let should_be = [MoveForward(3), TurnLeft(1), MoveForward(1), TurnRight(2)];
assert!(orders.eq(should_be.iter().cloned()));
}
推荐阅读
- python - 'TypeError("can't pickle generator objects"): Concurrent.future 与 Asyncio
- node.js - 如何使用 node js 创建谷歌云项目和服务帐户?
- c# - C# 8 使用声明范围混淆
- typescript - Vue Composition API TypeScript ref 类型不起作用
- c++ - 移动项目时 QTreeWidget 快速恢复
- security - 我们如何限制特定用户的脚本?
- python-3.x - 需要一个用于识别相等字符串然后分配给新列的 pandas 数据框的函数
- r - 从行中删除特定单词的字符串
- r - 如何在多列上加入数据框并在一个列上进行模糊匹配?
- node.js - 后端容器无法连接到数据库 - Sequelize、Node、Postgres、Docker