1 个不稳定版本
0.1.0 | 2024年8月11日 |
---|
在 算法 中排名 561
每月下载量 127
32KB
286 行
自动机编程
自动机是一种自动执行一系列操作的机器。它可以由一个状态图来描述,其中状态通过标记有输入符号的边连接,这些符号将使自动机跳转到连接的状态。此库通过使用简单实现(模块 simple_impl)或手动实现状态,提供了一种简单的流程来实施此类自动机。当没有更多的连接可用或输入结束时,自动机停止执行。在整个运行过程中,自动机使用相同的可变数据引用,并可以在状态转换期间执行自定义操作(操作取决于状态实现)。如果状态跳转期间发生错误,自动机可以带有错误退出。
将预定义字符串连接成 "FooBar" 的示例自动机
此自动机具有预定义的执行序列(没有输入可以控制执行状态的顺序)。这意味着它将一直运行到达到最后一个状态(顺序执行)。
use std::rc::Rc;
use automata_like_programming::{
automaton::AutomatonResult, automaton_state::{
new_shared_automaton_state, AutomatonState, SharedAutomatonState
}
};
use automata_like_programming::automaton::{Automaton, NextState};
// Example implementation of an automaton state that appends specified text into
// mutable buffer.
pub struct TestState {
id: u8,
text: &'static str,
next_state: Option<SharedAutomatonState<'static, u8, String, String>>
}
impl TestState {
pub fn new(
id: u8,
text: &'static str,
next_state: Option<SharedAutomatonState<'static, u8, String, String>>
) -> Self {
Self { id, text, next_state }
}
}
impl AutomatonState<'static, u8, String, String> for TestState {
fn get_id_owned(
&self
) -> u8 {
self.id
}
fn get_id(
&self
) -> &u8 {
&self.id
}
fn execute_next_connection(
&self,
data: &mut String
) -> Result<NextState<'static, u8, String, String>, String> {
data.push_str(self.text);
if let Option::Some(nxt_state) = &self.next_state {
Result::Ok(NextState::Continue(Rc::clone(nxt_state)))
} else {
Result::Ok(NextState::NotFound)
}
}
}
let mut automaton = Automaton::new(|| {
// First we create the "Bar" state as it's the last state and it doesn't connect to
// any other state.
let bar_state = new_shared_automaton_state(
TestState::new(2, "Bar", Option::None)
);
// Secondly we declare the "Foo" state which is connected to "Bar" state.
let foo_state = new_shared_automaton_state(
TestState::new(1, "Foo", Option::Some(Rc::clone(&bar_state)))
);
foo_state
});
let mut buffer = String::with_capacity(6);
let result = automaton.run(&mut buffer);
assert!(result.is_could_not_find_next_state());
assert_eq!("FooBar", buffer);
简单状态实现的示例模式匹配
此包提供了一个自动机状态的简单实现。它使用传递给自动机的数据提供的键(例如,数据包含迭代器)。每个状态都有连接,这些连接定义了与给定键匹配的进程、在匹配此连接时要执行的进程以及将变得活动的下一个状态。以下是一个查找给定字符串中 "ab" 模式的自动机的示例。
use automata_like_programming::{
automaton::{
Automaton,
AutomatonResult
},
automaton_state::new_shared_concrete_state,
simple_impl::simple_state::{
KeyProvidingData,
SimpleInterStateConnection,
SimpleStateImplementation
}
};
struct TextMatching<'a> {
text: &'a str,
matches: Vec<usize>,
iter: usize,
}
impl <'a> TextMatching<'a> {
pub fn new(
text: &'a str
) -> Self {
Self { text, matches: Vec::new(), iter: 0}
}
pub fn add_match(
&mut self, index: usize
) -> () {
self.matches.push(index);
}
}
impl <'a> KeyProvidingData<(usize, char)> for TextMatching<'a> {
fn next_key(
&mut self
) -> Option<(usize, char)> {
if self.iter >= self.text.len() {
Option::None
} else {
self.iter += 1;
Option::Some((self.iter - 1, self.text.chars().nth(self.iter)?))
}
}
}
fn char_matcher(
c: char,
reversed: bool
) -> impl Fn(&(usize, char)) -> bool {
move |k| (k.1 == c) ^ reversed
}
let mut matching_data = TextMatching::new("aabbacacaabab");
let mut automaton: Automaton<u32, TextMatching, String> = Automaton::new(|| {
let non_match_state = new_shared_concrete_state(SimpleStateImplementation::new(0));
non_match_state.borrow_mut().register_connection(
SimpleInterStateConnection::new_no_action(char_matcher('a', true), &non_match_state)
);
let a_state = new_shared_concrete_state(SimpleStateImplementation::new(1));
non_match_state.borrow_mut().register_connection(
SimpleInterStateConnection::new_no_action(char_matcher('a', false), &a_state)
);
a_state.borrow_mut().register_connection(
SimpleInterStateConnection::new_no_action(char_matcher('a', false), &a_state)
);
a_state.borrow_mut().register_connection(
SimpleInterStateConnection::new_no_action(char_matcher('b', true), &non_match_state)
);
let b_state = new_shared_concrete_state(SimpleStateImplementation::new(2));
a_state.borrow_mut().register_connection(
SimpleInterStateConnection::new(char_matcher('b', false),
|data: &mut TextMatching, key| {
data.add_match(key.0);
Result::Ok(())
}, &b_state)
);
b_state.borrow_mut().register_connection(
SimpleInterStateConnection::new_no_action(char_matcher('a', false), &a_state)
);
b_state.borrow_mut().register_connection(
SimpleInterStateConnection::new_no_action(char_matcher('a', true), &non_match_state)
);
non_match_state
});
let result = automaton.run(&mut matching_data);
assert!(result.is_empty_iter());
assert_eq!(matching_data.matches, vec![1, 9, 11]);