Repository: pandas-dev/pandas

Issue:
Series.str.casefold
`Series.str.lower` implements `str.lower`, as expected. There are also corresponding `Series` methods for the other Python 2 string casing methods. However, Python 3's `str.casefold` is missing. [Casefold](https://docs.python.org/3/library/stdtypes.html#str.casefold) improves string equality and other comparisons, because it handles a greater variety of characters, as per the Unicode Standard. It'd be nice to have `Series.str.casefold` in Pandas.

The current alternative is more verbose and is slower than `Series.str.lower`.

    pd.Series(s.casefold() if isinstance(s, str) else s for s in series)

Further, this alternative encourages a frustrating mistake -- forgetting to keep the original Series' index, which causes trouble if the new Series needs to be inserted into the same DataFrame as the original.


Apologies for double-posting. I used the wrong account for #25404 .


Discussion:
can u update with the doc reference for casefold in python docs 
certainly would take as an enhancement PR

Resolving patch:
diff --git a/pandas/core/strings.py b/pandas/core/strings.py
--- a/pandas/core/strings.py
+++ b/pandas/core/strings.py
@@ -2926,7 +2926,7 @@ def rindex(self, sub, start=0, end=None):
 
     _shared_docs['casemethods'] = ("""
     Convert strings in the Series/Index to %(type)s.
-
+    %(version)s
     Equivalent to :meth:`str.%(method)s`.
 
     Returns
@@ -2943,6 +2943,7 @@ def rindex(self, sub, start=0, end=None):
         remaining to lowercase.
     Series.str.swapcase : Converts uppercase to lowercase and lowercase to
         uppercase.
+    Series.str.casefold: Removes all case distinctions in the string.
 
     Examples
     --------
@@ -2989,12 +2990,15 @@ def rindex(self, sub, start=0, end=None):
     3              sWaPcAsE
     dtype: object
     """)
-    _shared_docs['lower'] = dict(type='lowercase', method='lower')
-    _shared_docs['upper'] = dict(type='uppercase', method='upper')
-    _shared_docs['title'] = dict(type='titlecase', method='title')
+    _shared_docs['lower'] = dict(type='lowercase', method='lower', version='')
+    _shared_docs['upper'] = dict(type='uppercase', method='upper', version='')
+    _shared_docs['title'] = dict(type='titlecase', method='title', version='')
     _shared_docs['capitalize'] = dict(type='be capitalized',
-                                      method='capitalize')
-    _shared_docs['swapcase'] = dict(type='be swapcased', method='swapcase')
+                                      method='capitalize', version='')
+    _shared_docs['swapcase'] = dict(type='be swapcased', method='swapcase',
+                                    version='')
+    _shared_docs['casefold'] = dict(type='be casefolded', method='casefold',
+                                    version='\n    .. versionadded:: 0.25.0\n')
     lower = _noarg_wrapper(lambda x: x.lower(),
                            docstring=_shared_docs['casemethods'] %
                            _shared_docs['lower'])
@@ -3010,6 +3014,9 @@ def rindex(self, sub, start=0, end=None):
     swapcase = _noarg_wrapper(lambda x: x.swapcase(),
                               docstring=_shared_docs['casemethods'] %
                               _shared_docs['swapcase'])
+    casefold = _noarg_wrapper(lambda x: x.casefold(),
+                              docstring=_shared_docs['casemethods'] %
+                              _shared_docs['casefold'])
 
     _shared_docs['ismethods'] = ("""
     Check whether all characters in each string are %(type)s.


Test patch:
diff --git a/pandas/tests/test_strings.py b/pandas/tests/test_strings.py
--- a/pandas/tests/test_strings.py
+++ b/pandas/tests/test_strings.py
@@ -76,7 +76,7 @@ def assert_series_or_index_equal(left, right):
     'len', 'lower', 'lstrip', 'partition',
     'rpartition', 'rsplit', 'rstrip',
     'slice', 'slice_replace', 'split',
-    'strip', 'swapcase', 'title', 'upper'
+    'strip', 'swapcase', 'title', 'upper', 'casefold'
 ], [()] * 100, [{}] * 100))
 ids, _, _ = zip(*_any_string_method)  # use method name as fixture-id
 
@@ -3424,3 +3424,12 @@ def test_method_on_bytes(self):
             expected = Series(np.array(
                 ['ad', 'be', 'cf'], 'S2').astype(object))
             tm.assert_series_equal(result, expected)
+
+    @pytest.mark.skipif(compat.PY2, reason='not in python2')
+    def test_casefold(self):
+        # GH25405
+        expected = Series(['ss', NA, 'case', 'ssd'])
+        s = Series(['ß', NA, 'case', 'ßd'])
+        result = s.str.casefold()
+
+        tm.assert_series_equal(result, expected)