Repository: pandas-dev/pandas

Issue:
replace method with comma separator does not work in pandas 0.24.1
### The latest version (0.24.1) does not replace comma separator, but 0.23.4 does.

```python
import pandas as pd

df = pd.DataFrame({'one': ["1,000", "2,000"], 'two': ["3,000", "4,000"]})
df = df.replace({',': ''}, regex=True)

print(pd.__version__)
print(df)
```

```
0.23.4
    one   two
0  1000  3000
1  2000  4000
```

```
0.24.1
     one    two
0  1,000  3,000
1  2,000  4,000
```

If other characters are used with a comma, it works normally
```
df = df.replace({'1,': ''}, regex=True)
```
```
     one    two
0    000  3,000
1  2,000  4,000
```


Discussion:
Hi, it is not related to commas. In your example @mr-yoo, if you try to replace `,0`, it also fails. The replacement works only if the pattern is the beginning of the string
```
df.replace({',0': ''}, regex=True)
```

```
0.23.4
   one  two
0  100  300
1  200  400
```

```
0.24.1
     one    two
0  1, 000  3,000
1  2,000  4,000
```

Can it be related to
```
op = np.vectorize(lambda x: bool(re.match(b, x)) if isinstance(x, str)
                  else False)
``` 
in managers.py? 

`re.match` checks only if the beginning of the string matches. Should it be `re.search`? From my tests, it seems to reproduce the previous behaviour.

@PetitLepton seems logical, so maybe introduced as part of https://github.com/pandas-dev/pandas/issues/20656

Would certainly welcome a PR to fix if you are up for one

Resolving patch:
diff --git a/pandas/core/internals/managers.py b/pandas/core/internals/managers.py
--- a/pandas/core/internals/managers.py
+++ b/pandas/core/internals/managers.py
@@ -552,9 +552,9 @@ def comp(s, regex=False):
             if isna(s):
                 return isna(values)
             if hasattr(s, 'asm8'):
-                return _compare_or_regex_match(maybe_convert_objects(values),
-                                               getattr(s, 'asm8'), regex)
-            return _compare_or_regex_match(values, s, regex)
+                return _compare_or_regex_search(maybe_convert_objects(values),
+                                                getattr(s, 'asm8'), regex)
+            return _compare_or_regex_search(values, s, regex)
 
         masks = [comp(s, regex) for i, s in enumerate(src_list)]
 
@@ -1897,11 +1897,11 @@ def _consolidate(blocks):
     return new_blocks
 
 
-def _compare_or_regex_match(a, b, regex=False):
+def _compare_or_regex_search(a, b, regex=False):
     """
     Compare two array_like inputs of the same shape or two scalar values
 
-    Calls operator.eq or re.match, depending on regex argument. If regex is
+    Calls operator.eq or re.search, depending on regex argument. If regex is
     True, perform an element-wise regex matching.
 
     Parameters
@@ -1917,7 +1917,7 @@ def _compare_or_regex_match(a, b, regex=False):
     if not regex:
         op = lambda x: operator.eq(x, b)
     else:
-        op = np.vectorize(lambda x: bool(re.match(b, x)) if isinstance(x, str)
+        op = np.vectorize(lambda x: bool(re.search(b, x)) if isinstance(x, str)
                           else False)
 
     is_a_array = isinstance(a, np.ndarray)


Test patch:
diff --git a/pandas/tests/frame/test_replace.py b/pandas/tests/frame/test_replace.py
--- a/pandas/tests/frame/test_replace.py
+++ b/pandas/tests/frame/test_replace.py
@@ -466,6 +466,13 @@ def test_regex_replace_dict_nested(self):
         assert_frame_equal(res3, expec)
         assert_frame_equal(res4, expec)
 
+    def test_regex_replace_dict_nested_non_first_character(self):
+        # GH 25259
+        df = pd.DataFrame({'first': ['abc', 'bca', 'cab']})
+        expected = pd.DataFrame({'first': ['.bc', 'bc.', 'c.b']})
+        result = df.replace({'a': '.'}, regex=True)
+        assert_frame_equal(result, expected)
+
     def test_regex_replace_dict_nested_gh4115(self):
         df = pd.DataFrame({'Type': ['Q', 'T', 'Q', 'Q', 'T'], 'tmp': 2})
         expected = DataFrame({'Type': [0, 1, 0, 0, 1], 'tmp': 2})