Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions deepdiff/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ def __init__(self,

self.obj: Any = obj
self.case_sensitive: bool = case_sensitive if isinstance(item, strings) else True
item = item if self.case_sensitive else (item.lower() if isinstance(item, str) else item)
item = item if self.case_sensitive or use_regexp else (item.lower() if isinstance(item, str) else item)
_exclude_exact, self.exclude_glob_paths = separate_wildcard_and_exact_paths(set(exclude_paths) if exclude_paths else None)
self.exclude_paths: SetOrdered = SetOrdered(_exclude_exact) if _exclude_exact else SetOrdered()
self.exclude_regex_paths: List[Pattern[str]] = [re.compile(exclude_regex_path) for exclude_regex_path in exclude_regex_paths]
Expand All @@ -127,7 +127,7 @@ def __init__(self,
item = str(item)
if self.use_regexp:
try:
item = re.compile(item)
item = re.compile(item, flags=0 if self.case_sensitive else re.IGNORECASE)
except TypeError as e:
raise TypeError(f"The passed item of {item} is not usable for regex: {e}") from None
self.strict_checking: bool = strict_checking
Expand Down Expand Up @@ -236,7 +236,7 @@ def __search_dict(self,
parents_ids_added = add_to_frozen_set(parents_ids, item_id)

new_parent = parent_text % (parent, item_key_str)
new_parent_cased = new_parent if self.case_sensitive else new_parent.lower()
new_parent_cased = new_parent if self.case_sensitive or self.use_regexp else new_parent.lower()

str_item = str(item)
if (self.match_string and str_item == new_parent_cased) or\
Expand Down Expand Up @@ -282,7 +282,7 @@ def __search_iterable(self,

def __search_str(self, obj: Union[str, bytes, memoryview], item: Union[str, bytes, memoryview, Pattern[str]], parent: str) -> None:
"""Compare strings"""
obj_text = obj if self.case_sensitive else (obj.lower() if isinstance(obj, str) else obj)
obj_text = obj if self.case_sensitive or self.use_regexp else (obj.lower() if isinstance(obj, str) else obj)

is_matched = False
if self.use_regexp and isinstance(item, type(re.compile(''))):
Expand Down
28 changes: 28 additions & 0 deletions tests/test_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,34 @@ def test_regex_in_string(self):
result = {"matched_values": {"root"}}
assert DeepSearch(obj, item, verbose_level=1, use_regexp=True) == result

@pytest.mark.parametrize('case_sensitive', [False, True])
@pytest.mark.parametrize('pattern, matching, nonmatching', [
(r'\D+', 'ABC', '123'),
(r'\S+', 'ABC', ' '),
(r'\W+', '!', 'ABC'),
(r'\Boo\B', 'book', 'oo'),
(r'\N{LATIN CAPITAL LETTER A}', 'A', 'b'),
(r'(?-i:ABC)', 'ABC', 'abc'),
])
def test_regex_preserves_pattern_syntax(self, pattern, matching, nonmatching, case_sensitive):
result = DeepSearch([matching, nonmatching], pattern, use_regexp=True, case_sensitive=case_sensitive)
assert result == {'matched_values': {'root[0]'}}

@pytest.mark.parametrize('pattern, obj, expected_path', [
(r"\['\D+'\]$", {'ABC': 1, '123': 2}, "root['ABC']"),
(r"\['(?-i:ABC)'\]$", {'ABC': 1, 'abc': 2}, "root['ABC']"),
])
def test_regex_preserves_path_syntax(self, pattern, obj, expected_path):
assert DeepSearch(obj, pattern, use_regexp=True) == {'matched_paths': {expected_path}}

@pytest.mark.parametrize('case_sensitive, expected_paths', [
(False, {'root[0]', 'root[1]'}),
(True, {'root[0]'}),
])
def test_regex_case_sensitivity(self, case_sensitive, expected_paths):
result = DeepSearch(['ABC', 'abc', '123'], '[A-Z]+', use_regexp=True, case_sensitive=case_sensitive)
assert result == {'matched_values': expected_paths}

def test_regex_does_not_match_the_regex_string_itself(self):
obj = ["We like python", "but not (?:p|t)ython"]
item = "(?:p|t)ython"
Expand Down