Dmitry Mikhailov

Все статьи
Дмитрий Михайлов6 мин чтения

Одинаковые строки не совпадают: как найти скрытые различия

Пробелы, похожие буквы и разные записи ё мешают точному сравнению. Разбираем, какие изменения можно сделать автоматически и почему совпавшее название ещё не означает дубль.

Два хромированных дверных ключа с разными вырезами и чёрными головками

Не удаляйте строку, пока не поняли расхождение

Если два названия выглядят одинаково, но точное сравнение считает их разными, посмотрите на символы, из которых они состоят. Затем задайте явные правила подготовки текста и проверьте, какие записи после них совпали. Удалять «дубликаты» до этой проверки рано: похожее написание может обозначать разные данные.

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

Нужно разделить два решения. Первое — считать ли строки равными по выбранным текстовым правилам. Второе — относятся ли записи к одному проекту, товару или человеку. Даже полное равенство названий не отвечает на второй вопрос. У разных объектов бывает одинаковое имя, а один объект может называться по-разному в двух системах.

Сохраните исходный столбец и работайте с копией. Это позволит увидеть, какое изменение создало совпадение, и вернуться назад при ошибке. Если сразу заменить весь исходный текст, вместо расследования получится новый набор данных без объяснения, откуда взялись его значения.

Шесть значений, которые выглядят как два

В учебном наборе четыре версии «Проект А» и две версии слова «ёлка». Первая строка содержит обычный пробел и кириллическую А. Во второй между словами стоит неразрывный пробел. У третьей добавлен пробел после последней буквы. В четвёртой последняя A латинская.

В двух остальных строках ё записана по-разному: одним символом U+0451 либо последовательностью е U+0435 и комбинируемого знака U+0308. На экране обе записи могут выглядеть как одна буква с двумя точками. При буквальном сравнении исходных последовательностей это разные строки.

Таблица сохраняет все шесть вариантов из приложения. Обозначение U+ показывает кодовую точку Unicode: например, U+0020 — обычный пробел, U+00A0 — неразрывный. Латинская A имеет код U+0041, кириллическая А — U+0410. Похожий рисунок не делает их одним символом; различие письменностей объясняется в справке Unicode.

Для диагностики возьмите одну неожиданно несовпавшую пару и выпишите позиции и коды символов. В «Проект А» при счёте с единицы пробел стоит на седьмой позиции, буква А — на восьмой. Завершающий пробел добавляет девятую позицию. Такой список показывает причину точнее, чем попытка разглядеть её в ячейке.

Различия в учебном наборе
6 / 6
СтрокаЧто измененоКод символа
Проект АОбычный пробел и кириллическая АU+0020; U+0410
Проект АНеразрывный пробелU+00A0
Проект А + пробел в концеЗавершающий обычный пробелU+0020
Проект AЛатинская AU+0041
ёлкаЁ одним символомU+0451
ёлкаЕ и отдельный знак двух точекU+0435; U+0308

У каждой операции должно быть своё основание

В приложении заданы три операции: нормализация NFC, замена U+00A0 на обычный пробел и удаление обычных пробелов по краям. Внутренние пробелы и регистр сохраняются. Это ограниченное правило для учебного набора, которое можно проверить на каждой строке.

NFC приводит канонически эквивалентные последовательности к общей форме. В нашем примере она позволяет сравнить две записи ё. Стандарт Unicode UAX #15 различает каноническую нормализацию и формы совместимости: более широкая замена может стирать различия, значимые для конкретного текста. Поэтому выбирать NFKC только потому, что она меняет больше символов, не стоит.

Замена неразрывного пробела — отдельное правило сравнения. NFC сама по себе не означает «убрать все различия, которые плохо видны». Для заголовка неразрывность может быть полезна при вёрстке, а для сопоставления названий — несущественна. Это причина иметь отдельный подготовленный столбец, сохраняя оригинал для отображения.

После трёх указанных операций первые три кириллических названия совпадают. Обе записи «ёлка» тоже совпадают. Название с латинской A остаётся самостоятельным. Получаются три уникальных значения вместо шести. В Python соответствующая функция описана в документации unicodedata.normalize. Проверять нужно конкретную форму и дополнительные замены, а не расплывчатую команду «нормализовать текст».

Похожие буквы лучше сначала помечать

Автоматическая замена латинской A на кириллическую А может исправить случайную опечатку в русском названии. Но то же правило способно испортить настоящий код, имя файла или английское имя. Одного зрительного сходства для решения недостаточно.

В Unicode UTS #39 описаны механизмы поиска визуально смешиваемых символов. Такое обнаружение полезно как сигнал для проверки. Оно не устанавливает, что две записи обозначают один объект, и не даёт универсального разрешения заменить все найденные буквы.

Для рабочего списка задайте разрешённый алфавит только там, где он действительно известен. Если поле по договорённости содержит код из латинских букв и цифр, кириллическая А — нарушение формата. Если это свободное название международного проекта, сочетание разных письменностей может быть допустимым. Одинаковая техническая находка приводит к разным действиям.

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

Совпадение после очистки ещё не разрешает объединение

Представим два проекта с названием «Каталог». Один завершён в прошлом году, другой только начат. После любой аккуратной нормализации названия совпадут, но объединение строк потеряет самостоятельный проект. Поэтому группы совпавшего текста сначала становятся кандидатами на проверку.

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

Контрпример для пробелов — «А Б» и «АБ». Выбранные учебные операции сохраняют их разными. Команда «удали все пробелы» склеит значения, хотя оснований для этого не было. В кодах внутренний пробел иногда значим; в свободном тексте он разделяет слова. Любое более широкое правило нужно проверять на подобных парах.

Полезный результат подготовки содержит исходное значение, новое значение и причину изменения. Например: «заменён U+00A0» или «удалён завершающий U+0020». Отдельно выводятся группы, где разные исходные строки сошлись в одну. Такой журнал показывает последствия каждого решения и позволяет проверить спорные случаи до удаления или объединения записей.

Как поставить проверяемую задачу ИИ или скрипту

Вместо «почисти список» сформулируйте разрешённые действия. Для нашего набора: «Сохрани все строки и исходные значения. Примени NFC, замени неразрывный пробел обычным, убери обычные пробелы только по краям. Похожие буквы разных алфавитов пометь, но не заменяй. Покажи изменённые строки, причины изменений и группы совпадений».

Сначала проверьте ответ на шести учебных значениях. Ожидаются три группы: кириллическое название, название с латинской A и слово «ёлка». Дополнительно подайте «А Б» и «АБ» как пару, которая обязана остаться разной. Если обе A или обе строки без внутреннего пробела объединились, инструмент применил лишнее правило.

В регулярной обработке те же условия удобно закрепить в скрипте с контрольным набором. Добавьте примеры из реального формата: допустимые алфавиты, пустые значения, значимые пробелы. Успех на учебной шестерке показывает лишь соответствие узкому правилу; он не охватывает все особенности вашего каталога.

После просмотра изменений утвердите правила для каждого поля отдельно. Название проекта, почтовый адрес и машинный идентификатор могут требовать разных подходов. Сохранённый оригинал и журнал позволят объяснить любое новое совпадение. Это и есть проверяемый итог очистки: известно, что изменилось, зачем и какие решения об объединении ещё предстоит принять.

Прочитать с ИИ

Разберите главную мысль и примените её к своей задаче.

ChatGPTClaude
Посмотреть промпт
Прочитай статью «Одинаковые строки не совпадают: как найти скрытые различия»: https://dmitrymikhailov.com/insights/invisible-text-differences Объясни её основную мысль и назови конкретные примеры, на которых держатся выводы. Отдели факты статьи от своих предположений. Затем спроси, какую задачу я решаю, и помоги применить подход из статьи: предложи первый шаг и способ проверить результат. Если страница недоступна, попроси меня вставить текст. Не придумывай её содержание.