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
use regex::Regex;
use super::TransformField;
use crate::{action::transform::result::TransformResult, error::BadRegexError};
#[derive(Debug)]
pub struct Extract {
re: Regex,
passthrough_if_not_found: bool,
}
#[allow(missing_docs)] #[derive(thiserror::Error, Debug)]
pub enum ExtractError {
#[error(transparent)]
BadRegex(#[from] BadRegexError),
#[error("Capture group not found but passthrough_if_not_found is not set")]
CaptureGroupNotFound,
}
impl Extract {
pub fn new(re: &str, passthrough_if_not_found: bool) -> Result<Self, ExtractError> {
let re = Regex::new(re).map_err(BadRegexError)?;
Ok(Self {
re,
passthrough_if_not_found,
})
}
}
impl TransformField for Extract {
type Err = ExtractError;
fn transform_field(&self, old_val: Option<&str>) -> Result<TransformResult<String>, Self::Err> {
let Some(field) = old_val else {
return Ok(TransformResult::Old(None));
};
let extracted = match extract_captures_from(&self.re, field) {
Some(v) => v,
None if self.passthrough_if_not_found => field.to_owned(),
None => return Err(ExtractError::CaptureGroupNotFound),
};
Ok(TransformResult::New(Some(extracted)))
}
}
fn extract_captures_from(regex: &Regex, from: &str) -> Option<String> {
regex.captures(from).map(|captures| {
captures
.iter()
.skip(1 )
.filter_map(|capt| Some(capt?.as_str()))
.collect()
})
}
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used)]
use super::*;
const FROM: &str = "HelloxWorld";
#[test]
fn one() {
let re = Regex::new("(?s)(.*)x").unwrap();
assert_eq!(extract_captures_from(&re, FROM).unwrap(), "Hello");
}
#[test]
fn several() {
let re = Regex::new("(?s)(.*)x(.*)").unwrap();
assert_eq!(extract_captures_from(&re, FROM).unwrap(), "HelloWorld");
}
#[test]
fn not_matched() {
let re = Regex::new("(?s)(.*)xxx(.*)").unwrap();
assert!(extract_captures_from(&re, FROM).is_none());
}
}