@@ -813,17 +813,50 @@ def replace(
813
813
)
814
814
return blocks
815
815
816
- def _replace_single (
816
+ def _replace_regex (
817
817
self ,
818
818
to_replace ,
819
819
value ,
820
820
inplace : bool = False ,
821
- regex : bool = False ,
822
821
convert : bool = True ,
823
822
mask = None ,
824
823
) -> List ["Block" ]:
825
- """ no-op on a non-ObjectBlock """
826
- return [self ] if inplace else [self .copy ()]
824
+ """
825
+ Replace elements by the given value.
826
+
827
+ Parameters
828
+ ----------
829
+ to_replace : object or pattern
830
+ Scalar to replace or regular expression to match.
831
+ value : object
832
+ Replacement object.
833
+ inplace : bool, default False
834
+ Perform inplace modification.
835
+ convert : bool, default True
836
+ If true, try to coerce any object types to better types.
837
+ mask : array-like of bool, optional
838
+ True indicate corresponding element is ignored.
839
+
840
+ Returns
841
+ -------
842
+ List[Block]
843
+ """
844
+ if not self ._can_hold_element (to_replace ):
845
+ # i.e. only ObjectBlock, but could in principle include a
846
+ # String ExtensionBlock
847
+ return [self ] if inplace else [self .copy ()]
848
+
849
+ rx = re .compile (to_replace )
850
+
851
+ new_values = self .values if inplace else self .values .copy ()
852
+ replace_regex (new_values , rx , value , mask )
853
+
854
+ block = self .make_block (new_values )
855
+ if convert :
856
+ nbs = block .convert (numeric = False )
857
+ else :
858
+ nbs = [block ]
859
+ return nbs
827
860
828
861
def _replace_list (
829
862
self ,
@@ -1598,14 +1631,16 @@ def _replace_coerce(
1598
1631
self = self .coerce_to_target_dtype (value )
1599
1632
return self .putmask (mask , value , inplace = inplace )
1600
1633
else :
1601
- return self ._replace_single (
1602
- to_replace ,
1603
- value ,
1604
- inplace = inplace ,
1605
- regex = regex ,
1606
- convert = False ,
1607
- mask = mask ,
1608
- )
1634
+ regex = _should_use_regex (regex , to_replace )
1635
+ if regex :
1636
+ return self ._replace_regex (
1637
+ to_replace ,
1638
+ value ,
1639
+ inplace = inplace ,
1640
+ convert = False ,
1641
+ mask = mask ,
1642
+ )
1643
+ return self .replace (to_replace , value , inplace = inplace , regex = False )
1609
1644
return [self ]
1610
1645
1611
1646
@@ -2506,72 +2541,26 @@ def replace(
2506
2541
# here with listlike to_replace or value, as those cases
2507
2542
# go through _replace_list
2508
2543
2509
- if is_re (to_replace ) or regex :
2510
- return self ._replace_single (to_replace , value , inplace = inplace , regex = True )
2511
- else :
2512
- return super ().replace (to_replace , value , inplace = inplace , regex = regex )
2513
-
2514
- def _replace_single (
2515
- self ,
2516
- to_replace ,
2517
- value ,
2518
- inplace : bool = False ,
2519
- regex : bool = False ,
2520
- convert : bool = True ,
2521
- mask = None ,
2522
- ) -> List ["Block" ]:
2523
- """
2524
- Replace elements by the given value.
2525
-
2526
- Parameters
2527
- ----------
2528
- to_replace : object or pattern
2529
- Scalar to replace or regular expression to match.
2530
- value : object
2531
- Replacement object.
2532
- inplace : bool, default False
2533
- Perform inplace modification.
2534
- regex : bool, default False
2535
- If true, perform regular expression substitution.
2536
- convert : bool, default True
2537
- If true, try to coerce any object types to better types.
2538
- mask : array-like of bool, optional
2539
- True indicate corresponding element is ignored.
2540
-
2541
- Returns
2542
- -------
2543
- List[Block]
2544
- """
2545
- inplace = validate_bool_kwarg (inplace , "inplace" )
2546
-
2547
- # to_replace is regex compilable
2548
- regex = regex and is_re_compilable (to_replace )
2544
+ regex = _should_use_regex (regex , to_replace )
2549
2545
2550
- # try to get the pattern attribute (compiled re) or it's a string
2551
- if is_re (to_replace ):
2552
- pattern = to_replace .pattern
2546
+ if regex :
2547
+ return self ._replace_regex (to_replace , value , inplace = inplace )
2553
2548
else :
2554
- pattern = to_replace
2549
+ return super (). replace ( to_replace , value , inplace = inplace , regex = False )
2555
2550
2556
- # if the pattern is not empty and to_replace is either a string or a
2557
- # regex
2558
- if regex and pattern :
2559
- rx = re .compile (to_replace )
2560
- else :
2561
- # if the thing to replace is not a string or compiled regex call
2562
- # the superclass method -> to_replace is some kind of object
2563
- return super ().replace (to_replace , value , inplace = inplace , regex = regex )
2564
2551
2565
- new_values = self .values if inplace else self .values .copy ()
2566
- replace_regex (new_values , rx , value , mask )
2552
+ def _should_use_regex (regex : bool , to_replace : Any ) -> bool :
2553
+ """
2554
+ Decide whether to treat `to_replace` as a regular expression.
2555
+ """
2556
+ if is_re (to_replace ):
2557
+ regex = True
2567
2558
2568
- # convert
2569
- block = self .make_block (new_values )
2570
- if convert :
2571
- nbs = block .convert (numeric = False )
2572
- else :
2573
- nbs = [block ]
2574
- return nbs
2559
+ regex = regex and is_re_compilable (to_replace )
2560
+
2561
+ # Don't use regex if the pattern is empty.
2562
+ regex = regex and re .compile (to_replace ).pattern != ""
2563
+ return regex
2575
2564
2576
2565
2577
2566
class CategoricalBlock (ExtensionBlock ):
0 commit comments