libsubconverter/models/
regex_match_config.rs

1use serde::Deserialize;
2
3use crate::utils::{
4    matcher::{
5        apply_compiled_rule_to_string, compile_rule, replace_with_compiled_regex, CompiledRule,
6    },
7    reg_replace,
8};
9use regex::Regex;
10
11/// Configuration for regex-based matching operations
12#[derive(Debug, Clone, Deserialize)]
13pub struct RegexMatchConfig {
14    #[serde(rename = "match")]
15    pub _match: String,
16    pub replace: String,
17    pub script: String,
18
19    // Non-serialized field to hold the compiled rule
20    #[serde(skip)]
21    pub compiled_rule: Option<CompiledRule>,
22    // Optionally store the compiled regex specifically for replacement if needed
23    #[serde(skip)]
24    pub compiled_regex_for_replace: Option<Regex>,
25}
26
27impl RegexMatchConfig {
28    pub fn new(_match: String, replace: String, script: String) -> Self {
29        let mut config = Self {
30            _match,
31            replace,
32            script,
33            compiled_rule: None,
34            compiled_regex_for_replace: None,
35        };
36
37        config.compile();
38        config
39    }
40
41    /// Compiles the regex pattern in the `_match` field.
42    /// This should be called after deserialization or creation.
43    pub fn compile(&mut self) {
44        self.compiled_rule = Some(compile_rule(&self._match));
45        // Also pre-compile the regex specifically for the replacement logic
46        // Use the same case-insensitivity as reg_find/compile_rule(Plain/Remarks)
47        self.compiled_regex_for_replace = Regex::new(&format!("(?i){}", self._match)).ok();
48    }
49
50    pub fn process(&self, remark: &mut String) {
51        let mut matched = false;
52
53        // Use compiled rule for matching if available
54        if let Some(compiled) = &self.compiled_rule {
55            // Use the version designed for simple string matching
56            matched = apply_compiled_rule_to_string(compiled, remark);
57        } else {
58            // Fallback to original method if not compiled (shouldn't happen if compile() is
59            // called)
60            matched = crate::utils::matcher::reg_find(remark, &self._match);
61        }
62
63        if matched {
64            // Use pre-compiled regex for replacement if available
65            if let Some(re) = &self.compiled_regex_for_replace {
66                *remark = replace_with_compiled_regex(remark, re, &self.replace, true, false);
67            } else {
68                // Fallback to original reg_replace if regex compilation failed during compile()
69                *remark = reg_replace(remark, &self._match, &self.replace, true, false);
70            }
71        }
72    }
73}
74
75/// Collection of regex match configurations
76pub type RegexMatchConfigs = Vec<RegexMatchConfig>;