Skip to content

Commit d2f745a

Browse files
committed
TST: added unit tests from PR #1179 and copied docstrings
1 parent 835476f commit d2f745a

File tree

2 files changed

+97
-9
lines changed

2 files changed

+97
-9
lines changed

pandas/core/strings.py

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -232,20 +232,25 @@ def str_count(arr, pat):
232232
return _na_map(f, arr)
233233

234234

235-
def str_contains(arr, pat):
235+
def str_contains(arr, pat, case=True):
236236
"""
237237
Check whether given pattern is contained in each string in the array
238238
239239
Parameters
240240
----------
241241
pat : string
242242
Character sequence or regular expression
243+
case : boolean, default True
244+
If True, case sensitive
243245
244246
Returns
245247
-------
246248
247249
"""
248-
regex = re.compile(pat)
250+
if not case:
251+
regex = re.compile(pat, re.IGNORECASE)
252+
else:
253+
regex = re.compile(pat)
249254
f = lambda x: bool(regex.search(x))
250255
return _na_map(f, arr)
251256

@@ -308,7 +313,7 @@ def str_upper(arr):
308313
return _na_map(lambda x: x.upper(), arr)
309314

310315

311-
def str_replace(arr, pat, repl, n=0):
316+
def str_replace(arr, pat, repl, n=0, case=True):
312317
"""
313318
Replace
314319
@@ -320,12 +325,17 @@ def str_replace(arr, pat, repl, n=0):
320325
Replacement sequence
321326
n : int, default 0 (all)
322327
Number of replacements to make from start
328+
case : boolean, default True
329+
If True, case sensitive
323330
324331
Returns
325332
-------
326333
replaced : array
327334
"""
328-
regex = re.compile(pat)
335+
if not case:
336+
regex = re.compile(pat, re.IGNORECASE)
337+
else:
338+
regex = re.compile(pat)
329339
def f(x):
330340
return regex.sub(repl, x, count=n)
331341

@@ -599,7 +609,8 @@ def wrapper(self):
599609
return self._wrap_result(result)
600610

601611
wrapper.__name__ = f.__name__
602-
wrapper.__doc__ = f.__doc__
612+
if f.__doc__:
613+
wrapper.__doc__ = f.__doc__
603614

604615
return wrapper
605616

@@ -610,10 +621,20 @@ def wrapper(self, pat):
610621
return self._wrap_result(result)
611622

612623
wrapper.__name__ = f.__name__
613-
wrapper.__doc__ = f.__doc__
624+
if f.__doc__:
625+
wrapper.__doc__ = f.__doc__
614626

615627
return wrapper
616628

629+
def copy(source):
630+
"Copy a docstring from another source function (if present)"
631+
def do_copy(target):
632+
if source.__doc__:
633+
target.__doc__ = source.__doc__
634+
return target
635+
return do_copy
636+
637+
617638
class StringMethods(object):
618639
"""
619640
Vectorized string functions for Series. NAs stay NA unless handled
@@ -632,47 +653,61 @@ def _wrap_result(self, result):
632653
return Series(result, index=self.series.index,
633654
name=self.series.name)
634655

656+
@copy(str_cat)
635657
def cat(self, others=None, sep=None, na_rep=None):
636658
result = str_cat(self.series, others=others, sep=sep, na_rep=na_rep)
637659
return self._wrap_result(result)
638660

661+
@copy(str_split)
639662
def split(self, pat, n=0):
640663
result = str_split(self.series, pat, n=n)
641664
return self._wrap_result(result)
642665

666+
@copy(str_get)
643667
def get(self, i):
644668
result = str_get(self.series, i)
645669
return self._wrap_result(result)
646670

671+
@copy(str_join)
647672
def join(self, sep):
648673
result = str_join(self.series, sep)
649674
return self._wrap_result(result)
650675

651-
def replace(self, pat, repl, n=0):
652-
result = str_replace(self.series, pat, repl, n=n)
676+
@copy(str_contains)
677+
def contains(self, pat, case=True):
678+
result = str_contains(self.series, pat, case=case)
679+
return self._wrap_result(result)
680+
681+
@copy(str_replace)
682+
def replace(self, pat, repl, n=0, case=True):
683+
result = str_replace(self.series, pat, repl, n=n, case=case)
653684
return self._wrap_result(result)
654685

686+
@copy(str_repeat)
655687
def repeat(self, repeats):
656688
result = str_repeat(self.series, repeats)
657689
return self._wrap_result(result)
658690

691+
@copy(str_pad)
659692
def pad(self, width, side='left'):
660693
result = str_pad(self.series, width, side=side)
661694
return self._wrap_result(result)
662695

696+
@copy(str_center)
663697
def center(self, width):
664698
result = str_center(self.series, width)
665699
return self._wrap_result(result)
666700

701+
@copy(str_slice)
667702
def slice(self, start=None, stop=None):
668703
result = str_slice(self.series, start, stop)
669704
return self._wrap_result(result)
670705

706+
@copy(str_slice)
671707
def slice_replace(self, i=None, j=None):
672708
raise NotImplementedError
673709

674710
count = _pat_wrapper(str_count)
675-
contains = _pat_wrapper(str_contains)
676711
startswith = _pat_wrapper(str_startswith)
677712
endswith = _pat_wrapper(str_endswith)
678713
findall = _pat_wrapper(str_findall)

pandas/tests/test_strings.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,59 @@ def test_get(self):
573573
expected = Series([u'b', u'd', np.nan, u'g'])
574574
tm.assert_series_equal(result, expected)
575575

576+
def test_more_contains(self):
577+
# PR #1179
578+
import re
579+
580+
s = Series(['A', 'B', 'C', 'Aaba', 'Baca', '', NA,
581+
'CABA', 'dog', 'cat'])
582+
583+
result = s.str.contains('a')
584+
expected = Series([False, False, False, True, True, False, np.nan,
585+
False, False, True])
586+
assert_series_equal(result, expected)
587+
588+
result = s.str.contains('a', case=False)
589+
expected = Series([True, False, False, True, True, False, np.nan,
590+
True, False, True])
591+
assert_series_equal(result, expected)
592+
593+
result = s.str.contains('Aa')
594+
expected = Series([False, False, False, True, False, False, np.nan,
595+
False, False, False])
596+
assert_series_equal(result, expected)
597+
598+
result = s.str.contains('ba')
599+
expected = Series([False, False, False, True, False, False, np.nan,
600+
False, False, False])
601+
assert_series_equal(result, expected)
602+
603+
result = s.str.contains('ba', case=False)
604+
expected = Series([False, False, False, True, True, False, np.nan,
605+
True, False, False])
606+
assert_series_equal(result, expected)
607+
608+
def test_more_replace(self):
609+
# PR #1179
610+
import re
611+
s = Series(['A', 'B', 'C', 'Aaba', 'Baca',
612+
'', NA, 'CABA', 'dog', 'cat'])
613+
614+
result = s.str.replace('A', 'YYY')
615+
expected = Series(['YYY', 'B', 'C', 'YYYaba', 'Baca', '', NA,
616+
'CYYYBYYY', 'dog', 'cat'])
617+
assert_series_equal(result, expected)
618+
619+
result = s.str.replace('A', 'YYY', case=False)
620+
expected = Series(['YYY', 'B', 'C', 'YYYYYYbYYY', 'BYYYcYYY', '', NA,
621+
'CYYYBYYY', 'dog', 'cYYYt'])
622+
assert_series_equal(result, expected)
623+
624+
result = s.str.replace('^.a|dog', 'XX-XX ', case=False)
625+
expected = Series(['A', 'B', 'C', 'XX-XX ba', 'XX-XX ca', '', NA,
626+
'XX-XX BA', 'XX-XX ', 'XX-XX t'])
627+
assert_series_equal(result, expected)
628+
576629
if __name__ == '__main__':
577630
nose.runmodule(argv=[__file__,'-vvs','-x','--pdb', '--pdb-failure'],
578631
exit=False)

0 commit comments

Comments
 (0)