use crate::error::ParseErrorType;
struct SplitResult {
original: String,
word: String,
tossi: String,
}
pub fn modify_pairs(string: &str) -> Result<Vec<(String, String, String)>, ParseErrorType> {
let mut temp_result: Vec<(String, String, String)> = vec![];
let content = are_balanced(string);
if !content.0 {
Err(ParseErrorType::AreNotBalanced)
} else {
let content = find_pairs_nums(content.1);
if !content.0 {
Err(ParseErrorType::NestedParentheses)
} else if !content.1 {
Err(ParseErrorType::IsNotBrace)
} else {
for item in 0..content.2.len() {
let result = split_tossi_word(string, content.2[item].open, content.2[item].close);
match result {
Err(e) => return Err(e),
Ok(split) => {
if split.word.is_empty() {
return Err(ParseErrorType::WordIsEmpty);
} else if split.tossi.is_empty() {
return Err(ParseErrorType::TossiIsEmpty);
}
temp_result.push((split.original, split.word, split.tossi));
}
}
}
Ok(temp_result)
}
}
}
fn split_tossi_word(
string: &str,
start_num: usize,
end_num: usize,
) -> Result<SplitResult, ParseErrorType> {
let temp = string.chars().collect::<Vec<_>>();
let temp_splited = temp[start_num + 1..end_num]
.iter()
.cloned()
.collect::<String>();
let temp: Vec<&str> = temp_splited.split(',').collect();
if temp.len() != 2 {
return Err(ParseErrorType::SplitTossiWord);
}
let word = temp[0].trim().replace(' ', "");
let tossi = temp[1].trim().replace(' ', "");
Ok(SplitResult {
original: temp_splited,
word,
tossi,
})
}
#[derive(Debug, PartialEq)]
struct BracketPair {
open: usize,
close: usize,
}
fn find_pairs_nums(temp_vec: Vec<(usize, i32, char)>) -> (bool, bool, Vec<BracketPair>) {
let mut brackets: Vec<BracketPair> = vec![];
let mut temp_open = 0;
for item in temp_vec {
if let '{' | '}' = item.2 {
if item.1 != 1 {
return (false, true, brackets);
} else if item.2 == '{' {
temp_open = item.0;
} else {
brackets.push(BracketPair {
open: temp_open,
close: item.0,
});
}
} else {
return (true, false, brackets);
}
}
(true, true, brackets)
}
enum Bracket {
Open(char),
Close(char),
}
impl Bracket {
pub fn new(c: char) -> Option<Bracket> {
match c {
'{' | '[' | '(' => Some(Bracket::Open(c)),
'}' => Some(Bracket::Close('{')),
']' => Some(Bracket::Close('[')),
')' => Some(Bracket::Close('(')),
_ => None,
}
}
}
fn are_balanced(string: &str) -> (bool, Vec<(usize, i32, char)>) {
let mut brackets: Vec<Bracket> = vec![];
let mut brackets_list: Vec<(usize, i32, char)> = vec![];
let mut i = 1;
for (j, c) in string.chars().enumerate() {
match Bracket::new(c) {
Some(Bracket::Open(char_bracket)) => {
brackets.push(Bracket::Open(char_bracket));
brackets_list.push((j, i, c));
i += 1;
}
Some(Bracket::Close(char_close_bracket)) => {
i -= 1;
brackets_list.push((j, i, c));
match brackets.pop() {
Some(Bracket::Open(char_open_bracket)) => {
if char_close_bracket != char_open_bracket {
return (false, brackets_list);
}
}
_ => return (false, brackets_list),
}
}
_ => (),
};
}
(brackets.is_empty(), brackets_list)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn _are_balanced() {
let temp = "(((185 + 223.85) * 15) - 543)/2";
let v = vec![
(0, 1, '('),
(1, 2, '('),
(2, 3, '('),
(15, 3, ')'),
(21, 2, ')'),
(28, 1, ')'),
];
let result = (true, v);
assert_eq!(result, are_balanced(temp));
let temp = "{[]";
let v = vec![(0, 1, '{'), (1, 2, '['), (2, 2, ']')];
let result = (false, v);
assert_eq!(result, are_balanced(temp));
}
#[test]
fn _find_pairs_nums() {
let temp: Vec<(usize, i32, char)> = vec![
(0, 1, '{'),
(6, 1, '}'),
(8, 1, '{'),
(16, 1, '}'),
(18, 1, '{'),
(24, 1, '}'),
];
let result = (
true,
true,
vec![
BracketPair { open: 0, close: 6 },
BracketPair { open: 8, close: 16 },
BracketPair {
open: 18,
close: 24,
},
],
);
assert_eq!(result, find_pairs_nums(temp));
let temp: Vec<(usize, i32, char)> =
vec![(0, 1, '{'), (6, 1, '}'), (8, 1, '['), (16, 1, ']')];
let result = (true, false, vec![BracketPair { open: 0, close: 6 }]);
assert_eq!(result, find_pairs_nums(temp));
let temp = vec![(0, 1, '{'), (1, 2, '['), (2, 2, ']'), (3, 4, '}')];
let result = (true, false, vec![]);
assert_eq!(result, find_pairs_nums(temp));
}
}