Skip to content

Commit

Permalink
Feat: regex
Browse files Browse the repository at this point in the history
  • Loading branch information
Furrior committed May 13, 2024
1 parent 5521acb commit 7f0cc04
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 6 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ debug = true
[dependencies]
translit = {version = "0.5.0", optional = true }
regex = {version = "1.10.4", optional = true }
regex-cache = {version = "0.2.1", optional = true }

[features]
default = [
Expand All @@ -23,5 +24,5 @@ default = [
]

transliteration = ["translit"]
regexp = ["regex"]
regexp = ["regex", "regex-cache"]

1 change: 1 addition & 0 deletions dmsrc/regexp.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#define rustutils_regex_replace(text, re, re_params, replacement) CALL_LIB(RUST_UTILS, "regex_replace")(text, re, re_params, replacement)
47 changes: 42 additions & 5 deletions src/regexp.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,56 @@
use regex::Regex;
use regex_cache::RegexCache;
use std::sync::Mutex;

const CACHE_SIZE: usize = 128;

fn init_regex_cache() -> RegexCache {
RegexCache::new(CACHE_SIZE)
}

static RE_CACHE: Mutex<Option<RegexCache>> = Mutex::new(None);


fn compile_regex(pattern: &str) -> regex::Regex {
let mut cache = RE_CACHE.lock().unwrap();
if let Some(ref mut cache) = *cache {
cache.compile(pattern).unwrap().clone()
} else {
*cache = Some(init_regex_cache());
init_regex_cache().compile(pattern).unwrap().clone()
}
}

byond_fn!(fn regex_replace (text, re, re_params, replacement) {
Some(regexp_replace(text, re, re_params, replacement))
});

fn regexp_replace(text: &str, re: &str, re_params: &str, replacement: &str) -> String {
let pattern = format!(r"(?{}){}", re_params, re);
let re = compile_regex(pattern.as_str());

re.replace_all(text, replacement).to_string()
}



#[cfg(test)]
mod tests {
use super::*;

#[test]
fn regexp_test() {
let pattern = r"(?i)\bго+л\b";
let pattern = r"\bго+л\b";

let re = Regex::new(pattern).unwrap();
let pattern_flags = "i";

let input = "Сука Гооооооооооооооол в гооооландские ворота.";

let output = re.replace_all(input, "поподание мячем");
let expected_output = "Сука попадание мячем в гооооландские ворота.";

let replacement = "попадание мячем";

assert_eq!(output, "Сука поподание мячем в гооооландские ворота.");
for _ in 1..2 {
assert_eq!(expected_output, regexp_replace(input, pattern, pattern_flags, replacement));
}
}
}
7 changes: 7 additions & 0 deletions tests/dm-tests.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
use std::process::{Command, Output};

#[cfg(feature = "transliteration")]
#[test]
fn transliteration() {
run_dm_tests("transliteration");
}

#[cfg(feature = "regexp")]
#[test]
fn regexp() {
run_dm_tests("regexp");
}

fn run_dm_tests(name: &str) {
std::env::remove_var("RUST_BACKTRACE");

Expand Down
19 changes: 19 additions & 0 deletions tests/dm/regexp.dme
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include "common.dm"

var/input = "Сука Гооооооооооооооол в гооооландские ворота."
var/pattern = @"\bго+л\b"
var/pattern_flags = "i"
var/replacement = "попадание мячем"

var/expected_output = "Сука попадание мячем в гооооландские ворота."

/test/proc/test_regexp_replace()
var/output = rustutils_regex_replace(input, pattern, pattern_flags, replacement)
ASSERT(output == expected_output)

/test/proc/test_regex_time()
var/start = world.timeofday
for(var/i in 1 to 1000)
var/output = rustutils_regex_replace(input, pattern, pattern_flags, replacement)
var/end = world.timeofday
ASSERT(end - start < 10)

0 comments on commit 7f0cc04

Please sign in to comment.