Вопрос или проблема
Я использую DeepDiff с exclude_regex_paths="['seqid']"
, чтобы исключить определенные поля, но замечаю, что исключается все, а не только поля, которые я хочу исключить. Реальные различия, вне пути, который нужно исключить, не отображаются.
Вот мой код:
from deepdiff import DeepDiff
data1 = {
"record1": {"seqid": "ABC123", "value": 1},
"record2": {"seqid": "DEF456", "value": 2}
}
data2 = {
"record1": {"seqid": "XYZ789", "value": 3}, # значение изменилось с 1 на 3
"record2": {"seqid": "UVW321", "value": 4} # значение изменилось с 2 на 4
}
diff = DeepDiff(data1, data2, exclude_regex_paths="['seqid']")
print(diff) # {} - Пустой вывод, но различия по значению должны быть показаны
Я ожидал, что это исключит только отличия ‘seqid’, оставив различия по значениям, но я получаю пустой дифф. Что я делаю не так? Я на версии DeepDiff 8.0.1.
Документация, к сожалению, не определяет синтаксис путей для использования.
Я нашел связанный, противоположный вопрос: DeepDiff exclude_paths regex не отфильтровывает пути
Я понял в чем проблема: неэкранированные квадратные скобки интерпретировались как определяющие множество символов, которое соответствует любому одному символу, который является либо '
, либо s
, либо e
, либо q
, либо i
, либо d
. И все пути, которые совпадают с DeepDiff, содержат как минимум две '
– поэтому все исключаются.
Исправление состоит в том, чтобы экранировать специальные символы регулярных выражений, в этом случае квадратные скобки: exclude_regex_paths="\['seqid'\]"
. Это работает правильно:
print(DeepDiff(data1, data2, exclude_regex_paths="\['seqid'\]"))
# {'values_changed': {"root['record1']['value']": {'new_value': 3, 'old_value': 1}, "root['record2']['value']": {'new_value': 4, 'old_value': 2}}}
Более осторожное, но многословное решение может быть:
diff = DeepDiff(
data1,
data2,
exclude_regex_paths=r"root\[.*?\]\['seqid'\]$"
)
Этот шаблон:
- Правильно экранирует скобки, чтобы соответствовать им буквально
- Использует
.*?
для не жадного поиска между частями - Использует
$
, чтобы убедиться, что мы только сопоставляем ‘seqid’ в конце пути
.
Ответ или решение
Когда вы используете библиотеку DeepDiff для сравнения данных и пытаетесь исключить определенные поля, но вместо этого наблюдаете, что всё исключается, это может быть связано с неправильной интерпретацией регулярных выражений. Рассмотрим вашу проблему более подробно.
Проблема
Вы используете параметр exclude_regex_paths
с регулярным выражением exclude_regex_paths="['seqid']"
. Ожидаете, что это исключит только поле seqid
, но вместо этого результат оказывается пустым. То есть, DeepDiff не показывает никаких различий между двумя наборами данных, хотя вы ожидаете увидеть изменения в полях value
.
Причина
Главная причина в том, что символы квадратных скобок [
и ]
в регулярных выражениях интерпретируются как начало и конец набора символов. Таким образом, выражение ['seqid']
воспринимается как соответствующее любому одному символу из множества: '
, s
, e
, q
, i
, d
. Так как все пути в структуре данных содержат один или несколько символов '
, DeepDiff пропускает все пути, совпадающие с вашим шаблоном, что приводит к пустому результату.
Решение
Чтобы исправить проблему, необходимо экранировать специальные символы в регулярном выражении. В вашем случае вы можете записать exclude_regex_paths="\['seqid'\]"
, чтобы явно указать, что вы хотите исключить именно саму строку ['seqid']
. Вот исправленный код:
from deepdiff import DeepDiff
data1 = {
"record1": {"seqid": "ABC123", "value": 1},
"record2": {"seqid": "DEF456", "value": 2}
}
data2 = {
"record1": {"seqid": "XYZ789", "value": 3},
"record2": {"seqid": "UVW321", "value": 4}
}
diff = DeepDiff(data1, data2, exclude_regex_paths="\['seqid'\]")
print(diff)
# {'values_changed': {"root['record1']['value']": {'new_value': 3, 'old_value': 1}, "root['record2']['value']": {'new_value': 4, 'old_value': 2}}}
Альтернативное решение
Вы также можете использовать более осторожный подход с более сложным регулярным выражением, которое чётко задаёт структуру пути:
diff = DeepDiff(
data1,
data2,
exclude_regex_paths=r"root\[.*?\]\['seqid'\]$"
)
В этом случае:
- Символы
[
и]
экранированы, что позволяет им соответствовать буквальному значению. - Конструкция
.*?
используется для не жадного соответствия между частями пути. - Символ
$
указывает, что совпадение должно происходить в конце пути, что исключает другие пути, содержащиеseqid
только в начале.
Заключение
Использование правильного синтаксиса регулярных выражений является ключевым при работе с функциями исключения в DeepDiff. Экранирование специальных символов и конструкция регистров позволяет вам точно определить, какие элементы вам нужно исключить, избегая случайного исключения всех полей. Оптовое представление же этих правил может гарантировать, что вы получите именно те результаты, которые ожидаете.