use crate::Builtins::Core::{
DixType, DixValue, IBuiltinMethod, BuiltinMethod,
};
use regex::Regex;
use std::collections::HashMap;
pub fn get_methods() -> HashMap<String, Box<dyn IBuiltinMethod>> {
let mut methods: HashMap<String, Box<dyn IBuiltinMethod>> = HashMap::new();
methods.insert(
"test".to_string(),
Box::new(BuiltinMethod::new_with_validator(
"test".to_string(),
2,
DixType::Bool,
test_impl,
"Tests if the regex pattern matches the given string".to_string(),
|args| {
args.len() == 2
&& args[0].get_type() == DixType::Regex
&& args[1].get_type() == DixType::String
},
)),
);
methods.insert(
"match".to_string(),
Box::new(BuiltinMethod::new_with_validator(
"match".to_string(),
2,
DixType::Array,
match_impl,
"Returns the first match and capture groups as an array".to_string(),
|args| {
args.len() == 2
&& args[0].get_type() == DixType::Regex
&& args[1].get_type() == DixType::String
},
)),
);
methods.insert(
"matchAll".to_string(),
Box::new(BuiltinMethod::new_with_validator(
"matchAll".to_string(),
2,
DixType::Array,
match_all_impl,
"Returns all matches as an array of arrays (each with capture groups)".to_string(),
|args| {
args.len() == 2
&& args[0].get_type() == DixType::Regex
&& args[1].get_type() == DixType::String
},
)),
);
methods.insert(
"replace".to_string(),
Box::new(BuiltinMethod::new_with_validator(
"replace".to_string(),
3,
DixType::String,
replace_impl,
"Replaces all matches with the replacement string".to_string(),
|args| {
args.len() == 3
&& args[0].get_type() == DixType::Regex
&& args[1].get_type() == DixType::String
&& args[2].get_type() == DixType::String
},
)),
);
methods.insert(
"split".to_string(),
Box::new(BuiltinMethod::new_with_validator(
"split".to_string(),
2,
DixType::Array,
split_impl,
"Splits the string by the regex pattern".to_string(),
|args| {
args.len() == 2
&& args[0].get_type() == DixType::Regex
&& args[1].get_type() == DixType::String
},
)),
);
methods.insert(
"isValid".to_string(),
Box::new(BuiltinMethod::new_with_validator(
"isValid".to_string(),
1,
DixType::Bool,
is_valid_impl,
"Checks if the regex pattern is valid".to_string(),
|args| args.len() == 1 && args[0].get_type() == DixType::Regex,
)),
);
methods
}
fn test_impl(args: &[DixValue]) -> Result<DixValue, String> {
let pattern = args[0].as_string();
let text = args[1].as_string();
let re = Regex::new(&pattern)
.map_err(|e| format!("Invalid regex pattern: {}", e))?;
Ok(DixValue::from_bool(re.is_match(&text)))
}
fn match_impl(args: &[DixValue]) -> Result<DixValue, String> {
let pattern = args[0].as_string();
let text = args[1].as_string();
let re = Regex::new(&pattern)
.map_err(|e| format!("Invalid regex pattern: {}", e))?;
if let Some(captures) = re.captures(&text) {
let mut result = Vec::new();
if let Some(full_match) = captures.get(0) {
result.push(DixValue::from_string(full_match.as_str().to_string()));
}
for i in 1..captures.len() {
if let Some(capture) = captures.get(i) {
result.push(DixValue::from_string(capture.as_str().to_string()));
} else {
result.push(DixValue::null());
}
}
Ok(DixValue::from_array(result))
} else {
Ok(DixValue::from_array(Vec::new()))
}
}
fn match_all_impl(args: &[DixValue]) -> Result<DixValue, String> {
let pattern = args[0].as_string();
let text = args[1].as_string();
let re = Regex::new(&pattern)
.map_err(|e| format!("Invalid regex pattern: {}", e))?;
let mut all_matches = Vec::new();
for captures in re.captures_iter(&text) {
let mut match_array = Vec::new();
if let Some(full_match) = captures.get(0) {
match_array.push(DixValue::from_string(full_match.as_str().to_string()));
}
for i in 1..captures.len() {
if let Some(capture) = captures.get(i) {
match_array.push(DixValue::from_string(capture.as_str().to_string()));
} else {
match_array.push(DixValue::null());
}
}
all_matches.push(DixValue::from_array(match_array));
}
Ok(DixValue::from_array(all_matches))
}
fn replace_impl(args: &[DixValue]) -> Result<DixValue, String> {
let pattern = args[0].as_string();
let text = args[1].as_string();
let replacement = args[2].as_string();
let re = Regex::new(&pattern)
.map_err(|e| format!("Invalid regex pattern: {}", e))?;
let result = re.replace_all(&text, replacement.as_str());
Ok(DixValue::from_string(result.to_string()))
}
fn split_impl(args: &[DixValue]) -> Result<DixValue, String> {
let pattern = args[0].as_string();
let text = args[1].as_string();
let re = Regex::new(&pattern)
.map_err(|e| format!("Invalid regex pattern: {}", e))?;
let parts: Vec<DixValue> = re
.split(&text)
.map(|s| DixValue::from_string(s.to_string()))
.collect();
Ok(DixValue::from_array(parts))
}
fn is_valid_impl(args: &[DixValue]) -> Result<DixValue, String> {
let pattern = args[0].as_string();
let is_valid = Regex::new(&pattern).is_ok();
Ok(DixValue::from_bool(is_valid))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_regex_test() {
let pattern = DixValue::from_regex(r"\d+".to_string()).unwrap();
let text = DixValue::from_string("abc123def".to_string());
let result = test_impl(&[pattern, text]).unwrap();
assert!(result.as_bool());
}
#[test]
fn test_regex_match() {
let pattern = DixValue::from_regex(r"(\w+)@(\w+)\.(\w+)".to_string()).unwrap();
let text = DixValue::from_string("user@example.com".to_string());
let result = match_impl(&[pattern, text]).unwrap();
let matches = result.as_array();
assert_eq!(matches.len(), 4); assert_eq!(matches[0].as_string(), "user@example.com");
assert_eq!(matches[1].as_string(), "user");
assert_eq!(matches[2].as_string(), "example");
assert_eq!(matches[3].as_string(), "com");
}
#[test]
fn test_regex_match_all() {
let pattern = DixValue::from_regex(r"\d+".to_string()).unwrap();
let text = DixValue::from_string("abc123def456ghi".to_string());
let result = match_all_impl(&[pattern, text]).unwrap();
let all_matches = result.as_array();
assert_eq!(all_matches.len(), 2);
assert_eq!(all_matches[0].as_array()[0].as_string(), "123");
assert_eq!(all_matches[1].as_array()[0].as_string(), "456");
}
#[test]
fn test_regex_replace() {
let pattern = DixValue::from_regex(r"\d+".to_string()).unwrap();
let text = DixValue::from_string("abc123def456".to_string());
let replacement = DixValue::from_string("X".to_string());
let result = replace_impl(&[pattern, text, replacement]).unwrap();
assert_eq!(result.as_string(), "abcXdefX");
}
#[test]
fn test_regex_split() {
let pattern = DixValue::from_regex(r",\s*".to_string()).unwrap();
let text = DixValue::from_string("a, b,c, d".to_string());
let result = split_impl(&[pattern, text]).unwrap();
let parts = result.as_array();
assert_eq!(parts.len(), 4);
assert_eq!(parts[0].as_string(), "a");
assert_eq!(parts[1].as_string(), "b");
assert_eq!(parts[2].as_string(), "c");
assert_eq!(parts[3].as_string(), "d");
}
#[test]
fn test_regex_is_valid() {
let valid_pattern = DixValue::from_regex(r"\d+".to_string()).unwrap();
let result = is_valid_impl(&[valid_pattern]).unwrap();
assert!(result.as_bool());
let invalid_pattern = DixValue::new(
crate::Builtins::Core::dix_value::ValueData::Regex("[invalid".to_string()),
DixType::Regex,
);
let result = is_valid_impl(&[invalid_pattern]).unwrap();
assert!(!result.as_bool());
}
}