Каталог решений - Сравнение двух строк. Функция

Сравнение двух строк. Функция

Сравнение двух строк. Функция

В наличии

Поиск совпадающих и различных подстрок в двух строках, приведённых к общей длине. Результат — таблица значений с №№ начал и окончаний одинаковых и различных фрагментов. Дихотомический обход, высокая скорость.

Категория:

Описание

Понадобилось мне 2 строки сравнить и определить, какие в них фрагменты совпадают, а какие различаются. Для удобства привёл строки к одной длине. Впрочем, при желании любые 2 строки можно порубать так, чтобы сравнивать как имеющие одинаковую длину. Ну и ничего, кроме хитрых регулярных выражений да посимвольного перебора не нашёл. RegExp не удалось припахать к выдаче результата в нужном мне виде (возможно, мои руки кривы), а посимвольно обходить длинные строки не хотелось. В итоге сделал эту, авось кому пригодится.

Функция ПолучитьРазличияДвухСтрок(Знач стро1,Знач стро2,тф=Неопределено,Знач рДельта=0)

    Если тф=Неопределено Тогда

        // это первая итерация, инициализируемся

        рМаксДлина=0;

        // результаты вернём в таблице значений, фиксирующей фрагменты: № начсим, № консим, ЕстьРазница (булево)

        тф=Новый ТаблицаЗначений;

        тф.Колонки.Добавить(«Начало»);

        тф.Колонки.Добавить(«Конец»);

        тф.Колонки.Добавить(«ЕстьРазница»);

        Если стро1=стро2 Тогда // разницы вообще нет

            стротф=тф.Добавить();

            стротф.Начало=1;

            стротф.Конец=СтрДлина(стро2);

            Возврат тф;

        Иначе

            рДлина1=СтрДлина(стро1);

            рДлина2=СтрДлина(стро2);

            Если рДлина1<>рДлина2 Тогда // можно обрезать под одну длину, можно и отказаться

                рМинДлина=Мин(рДлина1,рДлина2);

                рМаксДлина=Макс(рДлина1,рДлина2);

                Если рМинДлина=рДлина1 Тогда стро2=Лев(стро2,рМинДлина) КонецЕсли;

                Если рМинДлина=рДлина2 Тогда стро1=Лев(стро1,рМинДлина) КонецЕсли;

            КонецЕсли;

        КонецЕсли;

        // заполним дихотомически

        ПолучитьРазличияДвухСтрок(стро1,стро2,тф);

        // дообработаем разницу длин, если она была, дописав «хвост» более длинной строки

        Если рМаксДлина<>0 Тогда

            стротф=тф.Добавить();

            стротф.Начало=рМинДлина+1;

            стротф.Конец=рМаксДлина;

            стротф.ЕстьРазница=Истина; // априорно

        КонецЕсли;

        // грубо свернём (такая таблица никогда не будет очень большой, поэтому можно не изощряться)

        тф2=тф.СкопироватьКолонки(); старЕР=Неопределено; старНачало=0; старКонец=0;

        Для каждого стротф Из тф Цикл

            Если старЕР<>стротф.ЕстьРазница Тогда

                Если старЕР<>Неопределено Тогда // закончим предыдущую

                    стротф2=тф2.Добавить();

                    стротф2.Начало=старНачало;

                    стротф2.Конец=старКонец;

                    стротф2.ЕстьРазница=старЕР;

                КонецЕсли;

                старЕР=стротф.ЕстьРазница;

                старНачало=стротф.Начало;

            КонецЕсли;

            старКонец=стротф.Конец;

        КонецЦикла;

        Если старЕР<>Неопределено Тогда // закончим предыдущую

            стротф2=тф2.Добавить();

            стротф2.Начало=старНачало;

            стротф2.Конец=старКонец;

            стротф2.ЕстьРазница=старЕР;

        КонецЕсли;

        Возврат тф2;

    Иначе

        // собственно рекурсивное сравнение строк

        этстро=стро1; // строка-эталон

        обрстро=стро2; // обрабатываемая строка

        пози=Цел(СтрДлина(обрстро)/2);

        Если пози=0 Тогда Возврат «» КонецЕсли; // ненормальная ситуация

        кусэт1=Лев(этстро,пози);

        кусэт2=Сред(этстро,пози+1);

        кусобр1=Лев(обрстро,пози);

        кусобр2=Сред(обрстро,пози+1);

        изм1=(кусэт1<>кусобр1);

        изм2=(кусэт2<>кусобр2);

        // смотрим первый кусок

        Если не изм1 Тогда

            стротф=тф.Добавить();

            стротф.Начало=?(рДельта=0,1,рДельта);

            стротф.Конец=стротф.Начало+СтрДлина(кусобр1)-1;

            стротф.ЕстьРазница=Ложь;

        Иначе // эта часть различна, идём дальше, обрабатывая её как отдельную строку

            рНачало=?(рДельта=0,1,рДельта);

            рКонец=рНачало+СтрДлина(кусобр1)-1;

            Если рНачало=рКонец Тогда // финальная фаза, 1 символ разницы

                стротф=тф.Добавить();

                стротф.Начало=рНачало;

                стротф.Конец=рКонец;

                стротф.ЕстьРазница=Истина;

            Иначе

                ПолучитьРазличияДвухСтрок(кусэт1,кусобр1,тф,рДельта);

            КонецЕсли;

        КонецЕсли;

        // смотрим второй кусок

        рДельта=(пози+1)+рДельта-?(рДельта=0,0,1);

        Если не изм2 Тогда

            стротф=тф.Добавить();

            стротф.Начало=рДельта;

            стротф.Конец=стротф.Начало+СтрДлина(кусобр2)-1;

            стротф.ЕстьРазница=Ложь;

        Иначе // эта часть различна, идём дальше, обрабатывая её как отдельную строку

            рНачало=рДельта;

            рКонец=рНачало+СтрДлина(кусобр2)-1;

            Если рНачало=рКонец Тогда // финальная фаза, 1 символ разницы

                стротф=тф.Добавить();

                стротф.Начало=рНачало;

                стротф.Конец=рКонец;

                стротф.ЕстьРазница=Истина;

            Иначе

                ПолучитьРазличияДвухСтрок(кусэт2,кусобр2,тф,рДельта);

            КонецЕсли;

        КонецЕсли;

        // ничего не возвращаем, результат не важен

    КонецЕсли;

КонецФункции

Пример вызова:
тф=ПолучитьРазличияДвухСтрок(строка1,строка2);

 

has been added to your cart:
Оформление заказа