Expand a replacement template against the captured groups. */
(repl: &[char], chars: &[char], caps: &Caps, names: &[(String, usize)], out: &mut String)
| 126 | |
| 127 | /* Expand a replacement template against the captured groups. */ |
| 128 | fn expand(repl: &[char], chars: &[char], caps: &Caps, names: &[(String, usize)], out: &mut String) -> Result<(), ReError> { |
| 129 | let mut i = 0; |
| 130 | while i < repl.len() { |
| 131 | let ch = repl[i]; |
| 132 | if ch != '\\' { out.push(ch); i += 1; continue; } |
| 133 | i += 1; |
| 134 | let Some(&n) = repl.get(i) else { return Err(ReError::Syntax(String::from("bad replacement, trailing backslash"))); }; |
| 135 | match n { |
| 136 | '\\' => { out.push('\\'); i += 1; } |
| 137 | 'n' => { out.push('\n'); i += 1; } |
| 138 | 't' => { out.push('\t'); i += 1; } |
| 139 | 'r' => { out.push('\r'); i += 1; } |
| 140 | '0'..='9' => { |
| 141 | let mut num = 0usize; |
| 142 | while i < repl.len() && repl[i].is_ascii_digit() { |
| 143 | num = num * 10 + repl[i].to_digit(10).unwrap() as usize; |
| 144 | i += 1; |
| 145 | } |
| 146 | push_group(num, chars, caps, out); |
| 147 | } |
| 148 | 'g' => { |
| 149 | i += 1; |
| 150 | if repl.get(i) != Some(&'<') { return Err(ReError::Syntax(String::from("missing < in group reference"))); } |
| 151 | i += 1; |
| 152 | let mut name = String::new(); |
| 153 | while i < repl.len() && repl[i] != '>' { name.push(repl[i]); i += 1; } |
| 154 | if repl.get(i) != Some(&'>') { return Err(ReError::Syntax(String::from("missing > in group reference"))); } |
| 155 | i += 1; |
| 156 | let idx = resolve_name(&name, names)?; |
| 157 | push_group(idx, chars, caps, out); |
| 158 | } |
| 159 | other => { out.push('\\'); out.push(other); i += 1; } |
| 160 | } |
| 161 | } |
| 162 | Ok(()) |
| 163 | } |
| 164 | |
| 165 | fn resolve_name(name: &str, names: &[(String, usize)]) -> Result<usize, ReError> { |
| 166 | if !name.is_empty() && name.chars().all(|c| c.is_ascii_digit()) { |
no test coverage detected