@@ -212,62 +212,83 @@ impl ProcessMatcher {
212212 text : & ' a str ,
213213 process_replace_list : & [ & str ] ,
214214 ) -> ( bool , Cow < ' a , str > ) {
215- let mut result = String :: with_capacity ( text. len ( ) ) ;
216- let mut last_end = 0 ;
217215 match self {
218216 #[ cfg( not( feature = "dfa" ) ) ]
219217 ProcessMatcher :: LeftMost ( ac) => {
220- for mat in ac. leftmost_find_iter ( text) {
221- // SAFETY: `last_end` corresponds to the end of the previous match (or 0), and `mat.start()`
222- // is strictly greater than or equal to `last_end`. The match boundaries guaranteed by
218+ let mut iter = ac. leftmost_find_iter ( text) ;
219+ if let Some ( first_mat) = iter. next ( ) {
220+ let mut result = String :: with_capacity ( text. len ( ) ) ;
221+ // SAFETY: `first_mat.start()` is strictly greater than or equal to 0. The match boundaries guaranteed by
223222 // the automaton always fall exactly on valid UTF-8 character boundaries.
224- result. push_str ( unsafe { text. get_unchecked ( last_end..mat . start ( ) ) } ) ;
225- // SAFETY: The `mat .value()` returned is exactly an index mapped 1:1 during automaton construction
223+ result. push_str ( unsafe { text. get_unchecked ( 0 ..first_mat . start ( ) ) } ) ;
224+ // SAFETY: The `first_mat .value()` returned is exactly an index mapped 1:1 during automaton construction
226225 // with `process_replace_list`, so it will never go naturally out of bounds.
227226 result. push_str ( unsafe {
228- process_replace_list. get_unchecked ( mat . value ( ) as usize )
227+ process_replace_list. get_unchecked ( first_mat . value ( ) as usize )
229228 } ) ;
230- last_end = mat. end ( ) ;
229+ let mut last_end = first_mat. end ( ) ;
230+ for mat in iter {
231+ // SAFETY: `last_end` corresponds to the end of the previous match (or 0), and `mat.start()`
232+ // is strictly greater than or equal to `last_end`. The match boundaries guaranteed by
233+ // the automaton always fall exactly on valid UTF-8 character boundaries.
234+ result. push_str ( unsafe { text. get_unchecked ( last_end..mat. start ( ) ) } ) ;
235+ // SAFETY: The `mat.value()` returned is exactly an index mapped 1:1 during automaton construction
236+ // with `process_replace_list`, so it will never go naturally out of bounds.
237+ result. push_str ( unsafe {
238+ process_replace_list. get_unchecked ( mat. value ( ) as usize )
239+ } ) ;
240+ last_end = mat. end ( ) ;
241+ }
242+ // SAFETY: `last_end` falls exactly on the end of the final matching pattern,
243+ // naturally guaranteeing it exists on a valid UTF-8 character boundary.
244+ result. push_str ( unsafe { text. get_unchecked ( last_end..) } ) ;
245+ return ( true , Cow :: Owned ( result) ) ;
231246 }
232247 }
233248 ProcessMatcher :: Chinese ( ac) => {
234- for mat in ac. find_iter ( text) {
235- // SAFETY: `last_end` corresponds to the end of the previous match (or 0), and `mat.start()`
236- // is strictly greater than or equal to `last_end`. The match boundaries guaranteed by
237- // the automaton always fall exactly on valid UTF-8 character boundaries.
238- result. push_str ( unsafe { text. get_unchecked ( last_end..mat. start ( ) ) } ) ;
239- // SAFETY: The `mat.value()` returned is exactly an index mapped 1:1 during automaton construction
240- // with `process_replace_list`, so it will never go naturally out of bounds.
249+ let mut iter = ac. find_iter ( text) ;
250+ if let Some ( first_mat) = iter. next ( ) {
251+ let mut result = String :: with_capacity ( text. len ( ) ) ;
252+ result. push_str ( unsafe { text. get_unchecked ( 0 ..first_mat. start ( ) ) } ) ;
241253 result. push_str ( unsafe {
242- process_replace_list. get_unchecked ( mat . value ( ) as usize )
254+ process_replace_list. get_unchecked ( first_mat . value ( ) as usize )
243255 } ) ;
244- last_end = mat. end ( ) ;
256+ let mut last_end = first_mat. end ( ) ;
257+ for mat in iter {
258+ result. push_str ( unsafe { text. get_unchecked ( last_end..mat. start ( ) ) } ) ;
259+ result. push_str ( unsafe {
260+ process_replace_list. get_unchecked ( mat. value ( ) as usize )
261+ } ) ;
262+ last_end = mat. end ( ) ;
263+ }
264+ result. push_str ( unsafe { text. get_unchecked ( last_end..) } ) ;
265+ return ( true , Cow :: Owned ( result) ) ;
245266 }
246267 }
247268 ProcessMatcher :: Others ( ac) => {
248- for mat in ac. find_iter ( text) {
249- // SAFETY: `last_end` corresponds to the end of the previous match (or 0), and `mat.start()`
250- // is strictly greater than or equal to `last_end`. The match boundaries guaranteed by
251- // the automaton always fall exactly on valid UTF-8 character boundaries.
252- result. push_str ( unsafe { text. get_unchecked ( last_end..mat. start ( ) ) } ) ;
269+ let mut iter = ac. find_iter ( text) ;
270+ if let Some ( first_mat) = iter. next ( ) {
271+ let mut result = String :: with_capacity ( text. len ( ) ) ;
272+ result. push_str ( unsafe { text. get_unchecked ( 0 ..first_mat. start ( ) ) } ) ;
253273 // SAFETY: The pattern ID returned is an index bounded tightly bounded by
254274 // `process_replace_list` mapped directly from pattern initialization.
255275 result. push_str ( unsafe {
256- process_replace_list. get_unchecked ( mat . pattern ( ) . as_usize ( ) )
276+ process_replace_list. get_unchecked ( first_mat . pattern ( ) . as_usize ( ) )
257277 } ) ;
258- last_end = mat. end ( ) ;
278+ let mut last_end = first_mat. end ( ) ;
279+ for mat in iter {
280+ result. push_str ( unsafe { text. get_unchecked ( last_end..mat. start ( ) ) } ) ;
281+ result. push_str ( unsafe {
282+ process_replace_list. get_unchecked ( mat. pattern ( ) . as_usize ( ) )
283+ } ) ;
284+ last_end = mat. end ( ) ;
285+ }
286+ result. push_str ( unsafe { text. get_unchecked ( last_end..) } ) ;
287+ return ( true , Cow :: Owned ( result) ) ;
259288 }
260289 }
261290 }
262-
263- if last_end > 0 {
264- // SAFETY: `last_end` falls exactly on the end of the final matching pattern,
265- // naturally guaranteeing it exists on a valid UTF-8 character boundary.
266- result. push_str ( unsafe { text. get_unchecked ( last_end..) } ) ;
267- ( true , Cow :: Owned ( result) )
268- } else {
269- ( false , Cow :: Borrowed ( text) )
270- }
291+ ( false , Cow :: Borrowed ( text) )
271292 }
272293
273294 /// Deletes all matched patterns in the provided text.
@@ -293,47 +314,59 @@ impl ProcessMatcher {
293314 /// not to fail based on the matcher's behavior.
294315 #[ inline( always) ]
295316 pub fn delete_all < ' a > ( & self , text : & ' a str ) -> ( bool , Cow < ' a , str > ) {
296- let mut result = String :: with_capacity ( text. len ( ) ) ;
297- let mut last_end = 0 ;
298317 match self {
299318 #[ cfg( not( feature = "dfa" ) ) ]
300319 ProcessMatcher :: LeftMost ( ac) => {
301- for mat in ac. leftmost_find_iter ( text) {
302- // SAFETY: `last_end` corresponds to the end of the previous match (or 0), and `mat.start()`
303- // is strictly greater than or equal to `last_end`. The match boundaries guaranteed by
320+ let mut iter = ac. leftmost_find_iter ( text) ;
321+ if let Some ( first_mat) = iter. next ( ) {
322+ let mut result = String :: with_capacity ( text. len ( ) ) ;
323+ // SAFETY: `first_mat.start()` is strictly greater than or equal to 0. The match boundaries guaranteed by
304324 // the automaton always fall exactly on valid UTF-8 character boundaries.
305- result. push_str ( unsafe { text. get_unchecked ( last_end..mat. start ( ) ) } ) ;
306- last_end = mat. end ( ) ;
325+ result. push_str ( unsafe { text. get_unchecked ( 0 ..first_mat. start ( ) ) } ) ;
326+ let mut last_end = first_mat. end ( ) ;
327+ for mat in iter {
328+ // SAFETY: `last_end` corresponds to the end of the previous match (or 0), and `mat.start()`
329+ // is strictly greater than or equal to `last_end`. The match boundaries guaranteed by
330+ // the automaton always fall exactly on valid UTF-8 character boundaries.
331+ result. push_str ( unsafe { text. get_unchecked ( last_end..mat. start ( ) ) } ) ;
332+ last_end = mat. end ( ) ;
333+ }
334+ // SAFETY: `last_end` falls exactly on the end of the final matching pattern,
335+ // naturally guaranteeing it exists on a valid UTF-8 character boundary.
336+ result. push_str ( unsafe { text. get_unchecked ( last_end..) } ) ;
337+ return ( true , Cow :: Owned ( result) ) ;
307338 }
308339 }
309340 ProcessMatcher :: Chinese ( ac) => {
310- for mat in ac. find_iter ( text) {
311- // SAFETY: `last_end` corresponds to the end of the previous match (or 0), and `mat.start()`
312- // is strictly greater than or equal to `last_end`. The match boundaries guaranteed by
313- // the automaton always fall exactly on valid UTF-8 character boundaries.
314- result. push_str ( unsafe { text. get_unchecked ( last_end..mat. start ( ) ) } ) ;
315- last_end = mat. end ( ) ;
341+ let mut iter = ac. find_iter ( text) ;
342+ if let Some ( first_mat) = iter. next ( ) {
343+ let mut result = String :: with_capacity ( text. len ( ) ) ;
344+ result. push_str ( unsafe { text. get_unchecked ( 0 ..first_mat. start ( ) ) } ) ;
345+ let mut last_end = first_mat. end ( ) ;
346+ for mat in iter {
347+ result. push_str ( unsafe { text. get_unchecked ( last_end..mat. start ( ) ) } ) ;
348+ last_end = mat. end ( ) ;
349+ }
350+ result. push_str ( unsafe { text. get_unchecked ( last_end..) } ) ;
351+ return ( true , Cow :: Owned ( result) ) ;
316352 }
317353 }
318354 ProcessMatcher :: Others ( ac) => {
319- for mat in ac. find_iter ( text) {
320- // SAFETY: `last_end` corresponds to the end of the previous match (or 0), and `mat.start()`
321- // is strictly greater than or equal to `last_end`. The match boundaries guaranteed by
322- // the automaton always fall exactly on valid UTF-8 character boundaries.
323- result. push_str ( unsafe { text. get_unchecked ( last_end..mat. start ( ) ) } ) ;
324- last_end = mat. end ( ) ;
355+ let mut iter = ac. find_iter ( text) ;
356+ if let Some ( first_mat) = iter. next ( ) {
357+ let mut result = String :: with_capacity ( text. len ( ) ) ;
358+ result. push_str ( unsafe { text. get_unchecked ( 0 ..first_mat. start ( ) ) } ) ;
359+ let mut last_end = first_mat. end ( ) ;
360+ for mat in iter {
361+ result. push_str ( unsafe { text. get_unchecked ( last_end..mat. start ( ) ) } ) ;
362+ last_end = mat. end ( ) ;
363+ }
364+ result. push_str ( unsafe { text. get_unchecked ( last_end..) } ) ;
365+ return ( true , Cow :: Owned ( result) ) ;
325366 }
326367 }
327368 }
328-
329- if last_end > 0 {
330- // SAFETY: `last_end` falls exactly on the end of the final matching pattern,
331- // naturally guaranteeing it exists on a valid UTF-8 character boundary.
332- result. push_str ( unsafe { text. get_unchecked ( last_end..) } ) ;
333- ( true , Cow :: Owned ( result) )
334- } else {
335- ( false , Cow :: Borrowed ( text) )
336- }
369+ ( false , Cow :: Borrowed ( text) )
337370 }
338371}
339372
0 commit comments