У вас есть справочник с ключами A01 и A02. На вход подано три строки, и одна из них не присоединяется к справочнику, хотя на экране выглядит такой же. Причина прячется на уровне символов: латинская A и кириллическая А записаны разными кодами. Визуальное сходство не делает строки равными и не доказывает, что они описывают один и тот же объект.

Представьте себе учебный пример. Справочник содержит только латинские идентификаторы A01 и A02. На вход подано три записи: первая A01, третья A02, а вторая — А01, где первый символ кириллический. Откуда взялся этот второй ключ, мы не знаем. Задача здесь не исправить его автоматически, а зафиксировать разницу и сохранить строку для выяснения.

Проверьте код и имя первой буквы

Для трёх вымышленных строк ниже все первые символы имеют назначенные имена: LATIN CAPITAL LETTER A или CYRILLIC CAPITAL LETTER A. В общем случае unicodedata.name возвращает назначенное имя; если имени нет и аргумент default не задан, она возбуждает ValueError. В выводе нашего кода match означает точное совпадение со справочником, а review — необходимость проверки без изменения исходного ключа.

NFKC — форма нормализации Unicode: сначала выполняется разложение по совместимости, затем каноническая композиция. Это преобразование представления текста по правилам Unicode. Ниже мы проверяем его результат только для двух выбранных ключей; оно не подменяет решение о том, какие записи относятся к одному объекту.

Символ

   

Код и назначенное имя

A, латинская

   

Кодовая позиция U+0041; официальное имя — LATIN CAPITAL LETTER A; десятичное представление 65.

А, кириллическая

   

Кодовая позиция U+0410; официальное имя — CYRILLIC CAPITAL LETTER A; десятичное представление 1040.

Учебная схема: латинская A — U+0041 (65), кириллическая А — U+0410 (1040). NFKC — форма нормализации Unicode с разложением по совместимости и последующей канонической композицией. Для этой пары A01 и А01 остаются разными ключами; две строки совпали со справочником, одна требует проверки.
Авторская учебная схема, три ID вымышлены. NFKC — форма нормализации Unicode с разложением по совместимости и последующей канонической композицией. Она не делает эту пару латинского и кириллического ключей одинаковой. Две строки совпали со справочником, одна сохранена для уточнения без автоматической замены.

В официальной документации Python описаны имя символа и нормальные формы Unicode. Стандарт Unicode Security Mechanisms отдельно рассматривает визуально смешиваемые символы. Наш код ниже - простая диагностика конкретных ключей, а не полная реализация проверки безопасности по этому стандарту.

Все три исходные строки и результат

Исходные строки и результат диагностики

   

Результат без подмены ключа

Первая строка: A01

   

Первый символ — U+0041. Такой ключ точно присутствует в справочнике.

Вторая строка: А01

   

Первый символ — U+0410. Точного совпадения со справочником нет, поэтому запись помечается статусом review (нужна проверка).

Третья строка: A02

   

Первый символ — U+0041. Ключ есть в справочнике.

Два идентификатора точно совпали с эталонными, один требует проверки: 2 + 1 = 3 исходные записи. Пометка проверки не означает, что оператор ошибся при вводе, и не утверждает, что один человек фигурирует под двумя ID или что запись потеряна. Для любого из этих выводов нужна документация и источник самого идентификатора.

Полный пример для повторения

import unicodedata as ud
reference = {"A01": "known-1", "A02": "known-2"}
raw = ["A01", "\u041001", "A02"]
for n, key in enumerate(raw, 1):
    first = key[0]
    print(n, repr(key), f"U+{ord(first):04X}",
          ud.name(first), "match" if key in reference else "review")
latin, cyrillic = raw[:2]
print("equal =", latin == cyrillic)
print("NFKC_equal =", ud.normalize("NFKC", latin) == ud.normalize("NFKC", cyrillic))
assert latin != cyrillic
assert ud.normalize("NFKC", cyrillic) == cyrillic
assert sum(x in reference for x in raw) == 2

Ожидаемый вывод программы:

1 'A01' U+0041 LATIN CAPITAL LETTER A match
2 'А01' U+0410 CYRILLIC CAPITAL LETTER A review
3 'A02' U+0041 LATIN CAPITAL LETTER A match
equal = False
NFKC_equal = False

Строка "\u041001" начинается с escape-последовательности \u0410, задающей одну кириллическую букву; за ней идут цифры 0 и 1. Поэтому первый символ имеет код U+0410, и вся строка не равна латинской "A01". Приведённый код действительно сверяет ключи строго посимвольно: одинаковая длина и похожие очертания для совпадения недостаточны.

Почему NFKC не заменяет проверку смысла

В нашем примере NFKC оставляет кириллическую А на месте: нормализованные ключи всё равно не равны. Нормализация Unicode описывает канонические и совместимые представления — это не инструкция «считать любые похожие буквы одним знаком». При этом для других идентификаторов NFKC может изменить представление, поэтому сохранение наших двух ключей нельзя распространять на все возможные ID. Замена всех похожих букв по внешнему виду рискует соединить разные объекты. Даже если протокол проекта допускает исправление такого ввода, сначала получите основание, сохраните сырые данные, зафиксируйте правило и проверьте, не возникли ли после преобразования коллизии ключей. В нашем примере основания нет, так что второй ID остаётся неизменным.

Порядок проверки несовпавшего ключа

  • Покажите исходную строку, её длину, коды и имена подозрительных символов.
  • Сравнивайте с точным ID из исходного справочника, а не с похожей фамилией.
  • Отделите диагностический флаг от решения исправить значение.
  • При документированном исправлении сохраните пару «было → стало» и основание, затем убедитесь в уникальности нового ключа.
  • Без документального основания оставьте пометку проверки; сохраните все исходные строки, включая несовпавшую.

После выяснения смысла ключей можно вернуться к объединению таблиц по ID и проверке несовпадений. Эта статья решает более узкую задачу: почему два визуально сходных ключа не равны на уровне символов. Она не выбирает за исследователя, какие записи являются одним объектом.

Если для собственного исследовательского набора нужна помощь с правилами подготовки и проверкой расчёта, можно обсудить подготовку и проверку статистического анализа. Заранее согласуйте вопрос, состав исходных файлов и объём помощи. Автоматическое преобразование строк само по себе не подтверждает достоверность данных.