@@ -1354,21 +1354,69 @@ fn apply_single_operation(
13541354 apply_list_operation ( val, |list| apply_range ( & list, range) , "Slice" )
13551355 }
13561356 StringOp :: Filter { pattern } => {
1357- let re = get_cached_regex ( pattern) ?;
1357+ // Fast path for literal string matching (no regex metacharacters)
1358+ let is_literal = !pattern. contains ( [
1359+ '\\' , '.' , '*' , '+' , '?' , '^' , '$' , '|' , '[' , ']' , '(' , ')' , '{' , '}' ,
1360+ ] ) ;
1361+
13581362 match val {
1359- Value :: List ( list) => Ok ( Value :: List (
1360- list. into_iter ( ) . filter ( |s| re. is_match ( s) ) . collect ( ) ,
1361- ) ) ,
1362- Value :: Str ( s) => Ok ( Value :: Str ( if re. is_match ( & s) { s } else { String :: new ( ) } ) ) ,
1363+ Value :: List ( list) => {
1364+ if is_literal {
1365+ Ok ( Value :: List (
1366+ list. into_iter ( ) . filter ( |s| s. contains ( pattern) ) . collect ( ) ,
1367+ ) )
1368+ } else {
1369+ let re = get_cached_regex ( pattern) ?;
1370+ Ok ( Value :: List (
1371+ list. into_iter ( ) . filter ( |s| re. is_match ( s) ) . collect ( ) ,
1372+ ) )
1373+ }
1374+ }
1375+ Value :: Str ( s) => {
1376+ if is_literal {
1377+ Ok ( Value :: Str ( if s. contains ( pattern) {
1378+ s
1379+ } else {
1380+ String :: new ( )
1381+ } ) )
1382+ } else {
1383+ let re = get_cached_regex ( pattern) ?;
1384+ Ok ( Value :: Str ( if re. is_match ( & s) { s } else { String :: new ( ) } ) )
1385+ }
1386+ }
13631387 }
13641388 }
13651389 StringOp :: FilterNot { pattern } => {
1366- let re = get_cached_regex ( pattern) ?;
1390+ // Fast path for literal string matching (no regex metacharacters)
1391+ let is_literal = !pattern. contains ( [
1392+ '\\' , '.' , '*' , '+' , '?' , '^' , '$' , '|' , '[' , ']' , '(' , ')' , '{' , '}' ,
1393+ ] ) ;
1394+
13671395 match val {
1368- Value :: List ( list) => Ok ( Value :: List (
1369- list. into_iter ( ) . filter ( |s| !re. is_match ( s) ) . collect ( ) ,
1370- ) ) ,
1371- Value :: Str ( s) => Ok ( Value :: Str ( if re. is_match ( & s) { String :: new ( ) } else { s } ) ) ,
1396+ Value :: List ( list) => {
1397+ if is_literal {
1398+ Ok ( Value :: List (
1399+ list. into_iter ( ) . filter ( |s| !s. contains ( pattern) ) . collect ( ) ,
1400+ ) )
1401+ } else {
1402+ let re = get_cached_regex ( pattern) ?;
1403+ Ok ( Value :: List (
1404+ list. into_iter ( ) . filter ( |s| !re. is_match ( s) ) . collect ( ) ,
1405+ ) )
1406+ }
1407+ }
1408+ Value :: Str ( s) => {
1409+ if is_literal {
1410+ Ok ( Value :: Str ( if s. contains ( pattern) {
1411+ String :: new ( )
1412+ } else {
1413+ s
1414+ } ) )
1415+ } else {
1416+ let re = get_cached_regex ( pattern) ?;
1417+ Ok ( Value :: Str ( if re. is_match ( & s) { String :: new ( ) } else { s } ) )
1418+ }
1419+ }
13721420 }
13731421 }
13741422 StringOp :: Sort { direction } => {
@@ -1429,16 +1477,24 @@ fn apply_single_operation(
14291477 flags,
14301478 } => {
14311479 if let Value :: Str ( s) = val {
1432- // Early exit for simple string patterns (not regex)
1433- if !flags. contains ( 'g' )
1434- && !pattern. contains ( [
1435- '\\' , '.' , '*' , '+' , '?' , '^' , '$' , '|' , '[' , ']' , '(' , ')' , '{' , '}' ,
1436- ] )
1437- && !s. contains ( pattern)
1438- {
1439- return Ok ( Value :: Str ( s) ) ;
1480+ // Fast path for literal string replacement (no regex metacharacters or special flags)
1481+ let is_literal = !pattern. contains ( [
1482+ '\\' , '.' , '*' , '+' , '?' , '^' , '$' , '|' , '[' , ']' , '(' , ')' , '{' , '}' ,
1483+ ] ) ;
1484+
1485+ // Only use fast path if no special regex flags (case-insensitive, multiline, etc.)
1486+ let has_special_flags = flags. chars ( ) . any ( |c| c != 'g' ) ;
1487+
1488+ if is_literal && !has_special_flags {
1489+ let result = if flags. contains ( 'g' ) {
1490+ s. replace ( pattern, replacement)
1491+ } else {
1492+ s. replacen ( pattern, replacement, 1 )
1493+ } ;
1494+ return Ok ( Value :: Str ( result) ) ;
14401495 }
14411496
1497+ // Regex path for complex patterns
14421498 let pattern_to_use = if flags. is_empty ( ) {
14431499 pattern. clone ( )
14441500 } else {
0 commit comments