1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
use rlua::prelude::*;
use regex;
pub struct LuaRegex(regex::Regex);
pub struct LuaCapture<'a>(regex::Captures<'a>);
impl LuaUserData for LuaRegex {
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_method("match", |_, this: &LuaRegex, val: String| {
Ok(this.0.is_match(&val))
});
methods.add_method("replace_all", |_, this: &LuaRegex, (val, patt): (String, String)| {
Ok(this.0.replace_all(&val, patt.as_str()).into_owned())
});
methods.add_method("capture", |_, this: &LuaRegex, val: String| {
Ok(this.0.captures(Box::leak(val.into_boxed_str())).map(LuaCapture))
});
}
}
impl<'a> LuaUserData for LuaCapture<'a> {
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_method("get", |_, this: &LuaCapture, index: usize| {
Ok(this.0.get(index).map(|s| s.as_str().to_string()))
});
methods.add_method("name", |_, this: &LuaCapture, name: String| {
Ok(this.0.name(&name).map(|s| s.as_str().to_string()))
});
methods.add_method("to_table", |_, this: &LuaCapture, _: ()| {
Ok(this.0.iter().filter_map(|s| s).map(|s| s.as_str().to_string()).collect::<Vec<String>>())
})
}
}
pub fn init(lua: &Lua) -> crate::Result<()> {
let module = lua.create_table()?;
module.set("new", lua.create_function(|_, expr: String| {
regex::Regex::new(&expr).map(LuaRegex).map_err(LuaError::external)
})?)?;
lua.globals().set("regex", module)?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn lua_regex_replace_all () {
let lua = Lua::new();
init(&lua).unwrap();
lua.exec::<_, ()>(r#"
local regex = regex.new([[(?P<y>\d{4})-(?P<m>\d{2})-(?P<d>\d{2})]])
local before = "2012-03-14, 2013-01-01 and 2014-07-05"
local result = regex:replace_all(before, "$m/$d/$y")
assert(result == "03/14/2012, 01/01/2013 and 07/05/2014")
"#, None).unwrap();
}
#[test]
fn lua_regex_match () {
let lua = Lua::new();
init(&lua).unwrap();
lua.exec::<_, ()>(r#"
local regex = regex.new([[^\d{4}-\d{2}-\d{2}$]])
local date = "2014-01-01"
local result = regex:match(date)
assert(result == true)
"#, None).unwrap();
}
#[test]
fn lua_regex_captures () {
let lua = Lua::new();
init(&lua).unwrap();
lua.exec::<_, ()>(r#"
local regex = regex.new([['([^']+)'\s+\((\d{4})\)]])
local val = "Not my favorite movie: 'Citizen Kane' (1941)"
local result = regex:capture(val):to_table()
assert(result ~= nil)
assert(result[1] == "'Citizen Kane' (1941)")
assert(result[2] == "Citizen Kane")
assert(result[3] == "1941")
"#, None).unwrap();
}
}