formatparse_core/parser/
mod.rs1pub mod pattern;
3pub mod regex;
4
5pub const MAX_PATTERN_LENGTH: usize = 10_000;
7pub const MAX_INPUT_LENGTH: usize = 10_000_000; pub const MAX_FIELDS: usize = 100;
9pub const MAX_FIELD_NAME_LENGTH: usize = 200;
10pub const MAX_WIDTH_PRECISION: usize = 1000;
12
13pub fn validate_pattern_length(pattern: &str) -> Result<(), String> {
15 if pattern.len() > MAX_PATTERN_LENGTH {
16 return Err(format!(
17 "Pattern length {} exceeds maximum allowed length of {} characters",
18 pattern.len(),
19 MAX_PATTERN_LENGTH
20 ));
21 }
22 Ok(())
23}
24
25pub fn validate_input_length(input: &str) -> Result<(), String> {
27 if input.len() > MAX_INPUT_LENGTH {
28 return Err(format!(
29 "Input length {} exceeds maximum allowed length of {} characters",
30 input.len(),
31 MAX_INPUT_LENGTH
32 ));
33 }
34 Ok(())
35}
36
37pub fn validate_field_name(field_name: &str) -> Result<(), String> {
39 if field_name.len() > MAX_FIELD_NAME_LENGTH {
40 return Err(format!(
41 "Field name length {} exceeds maximum allowed length of {} characters",
42 field_name.len(),
43 MAX_FIELD_NAME_LENGTH
44 ));
45 }
46
47 if field_name.contains('\0') {
49 return Err("Field name contains null byte".to_string());
50 }
51
52 Ok(())
53}
54
55pub fn count_capturing_groups(pattern: &str) -> usize {
57 use fancy_regex::Regex;
58 match Regex::new(pattern) {
59 Ok(re) => re.captures_len().saturating_sub(1),
60 Err(_) => usize::MAX,
61 }
62}
63
64#[cfg(test)]
65mod count_capturing_groups_tests {
66 use super::count_capturing_groups;
67
68 #[test]
69 fn named_group_counts_as_one() {
70 assert_eq!(count_capturing_groups(r"(?P<foo>\d+)"), 1);
71 }
72
73 #[test]
74 fn named_group_with_nested_capture() {
75 assert_eq!(count_capturing_groups(r"(?P<outer>\d(\d))"), 2);
76 }
77
78 #[test]
79 fn non_capturing_zero() {
80 assert_eq!(count_capturing_groups(r"(?:ab)"), 0);
81 }
82
83 #[test]
84 fn plain_capture_plus_named() {
85 assert_eq!(count_capturing_groups(r"(\w)(?P<n>\d+)"), 2);
86 }
87
88 #[test]
89 fn backreference_not_counted_as_capture_here() {
90 assert_eq!(count_capturing_groups(r"(?P<x>a)(?P=x)"), 1);
91 }
92
93 #[test]
94 fn unicode_escape_not_counted_as_capture() {
95 assert_eq!(count_capturing_groups(r"\u{28}abc"), 0);
96 }
97
98 #[test]
99 fn hex_escape_not_counted_as_capture() {
100 assert_eq!(count_capturing_groups(r"\x28abc"), 0);
101 }
102}