Как в C# правильно сравнивать строки
В обоих случаях результат True , хотя String является классом и оператор == должен был сравнить ссылки. IlDasm показал, что создаются 2 переменные и сравниваются согласно методам Equals и == (op_Equality)
IL_0000: nop IL_0001: ldstr "s" IL_0006: stloc.0 IL_0007: ldstr "s" IL_000c: stloc.1 IL_000d: ldstr "eq: " IL_0012: ldloc.0 IL_0013: ldloc.1 IL_0014: callvirt instance bool [mscorlib]System.String::Equals(string) IL_0019: box [mscorlib]System.Boolean IL_001e: call string [mscorlib]System.String::Concat(object, object) IL_0023: call void [mscorlib]System.Console::WriteLine(string) IL_0028: nop IL_0029: ldstr "==: " IL_002e: ldloc.0 IL_002f: ldloc.1 IL_0030: call bool [mscorlib]System.String::op_Equality(string, string) IL_0035: box [mscorlib]System.Boolean IL_003a: call string [mscorlib]System.String::Concat(object, object)
Отслеживать
задан 31 янв 2017 в 20:56
Vadim Prokopchuk Vadim Prokopchuk
2,722 2 2 золотых знака 17 17 серебряных знаков 41 41 бронзовый знак
Оператор == сравнивает лишь ссылки (и тем самым j,sxyj бесполезен) лишь в Java. В C#, в отличие от Java, есть перегрузка операторов.
31 янв 2017 в 21:41
3 ответа 3
Сортировка: Сброс на вариант по умолчанию
В C# правильно сравнивать строки и через == , и через Equals . Но более предпочтительным будет сравнивать через == .
Почему так?
Метод Equals подразумевает сравнение значений объектов ссылочного типа, он объявлен как virtual и для строк он перегружен и сравнивает их, как и предполагается, по значению. В Ваших классах Вы должны давать свою реализацию для него. Иначе он будет вести себя как ReferenceEquals и для ссылок, которые указывают не на один объект будет давать false , хоть они и будут равны по значению.
Оператор == для строк представляют свою реализацию, отличную от стандартной для всех других объектов ссылочного типа. Если сравниваемые ссылки имеют тип System.String , то он сначала сравнит указывают ли ссылки на один тот же объект и если нет, то будет сравнивать две ссылки типа System.String по значению.
Но маленькое замечание, если мы сравниваем объект типа System.String ( string ) с объектом типа System.Object (object), который указывает на строку, они будут сравниваться по значениям.
string str = "str"; object obj = "str"; bool result = str.Equals(obj);
result будет равен true , так как obj приведётся к типу string , потому что метод Equals мы вызвали у строки (объекта типа string ).
Но если мы сравниваем объект типа System.Object (object), который указывает на строку, с объектом типа System.String ( string ) они будут сравниваться по ссылке.
string str = "str"; object obj = "str"; bool result = obj.Equals(str);
result будет равен false , так как str приведётся к типу object , потому что метод Equals мы вызвали у объекта типа object .
Поэтому в данном случае важно привести object к типу string
Сравнение строк в C++: три основных метода
В этом руководстве мы изучим методы сравнения строк в C++. Давайте предположим, что нам необходимо ввести свое имя и пароль для входа на определенный веб-сайт. Для подобных случаев на серверной части мы должны собрать и написать скрипт для проверки и сравнения входной строки со строкой, хранящейся в базе данных.
Итак, на таком простом примере мы рассмотрим несколько способов сравнения строк в языке C++.
Методы сравнения строк в C++
Строки в C++ можно сравнивать с помощью любого из следующих методов:
- Строковая функция strcmp()
- Встроенная функция compare()
- Реляционные операторы С++ ( ‘==’, ‘!=’)
1: Строковая функция strcmp()
C++ имеет встроенные функции для управления и обработки данных строкового типа. Чтобы сравнить две строки, мы можем использовать функцию strcmp().
strcmp() — это библиотечная функция C, используемая для сравнения двух строк лексикографическим способом.
Синтаксис функции выглядит так:
int strcmp ( const char * str1, const char * str2 );
Функция возвращает 0, если строки одинаковы.
Входная строка должна быть массивом символов в стиле C.
При сравнении строк функция strcmp() учитывает регистр.
#include using namespace std; #include int main()
В результате вы получите:
String 1:JournalDEV String 2:JournalDEv The input strings are not equal.
#include using namespace std; #include int main()
Результат будет выглядеть так:
String 1:Python String 2:Python Both the input strings are equal.
2: Функция compare()
C++ имеет встроенную функцию compare(), которая нужна для быстрого сравнения двух строк.
Функция сравнивает две строки и возвращает следующие значения в зависимости от результата сравнения:
int compare (const string& string-name) const;
А теперь давайте рассмотрим пару примеров. Пример 1:
#include using namespace std; int main()
В приведенном выше примере мы сравнили строку 1 со строкой 2. Как видите, обе строки лексикографически одинаковы, потому функция возвращает 0.
String 1:Python String 2:Python Both the input strings are equal.
#include using namespace std; int main()
В приведенном выше фрагменте кода мы снова сравнили строку с другой входной строкой с помощью функции compare().
String 1:Python Strings are equal. String 2:JournalDEV Strings are not Equal.
3: Реляционные операторы в C++
Реляционные операторы C++, такие как «==» и «!=», можно легко использовать для сравнения строк.
Синтаксис их выглядит следующим образом:
string1 == string 2 или string1 != string2
Давайте взглянем на первый пример с использованием оператора ==:
#include using namespace std; int main() < string str_inp1; string str_inp2; cout>str_inp1; cout>str_inp2; if (str_inp1 == str_inp2) cout
Он вернет такой результат:
Enter the String 1: Python Enter the String 2: PythoN Strings are not equal
Во втором примере мы попробуем использовать оператор !=:
#include using namespace std; int main() < string str_inp1; string str_inp2; cout>str_inp1; cout>str_inp2; if (str_inp1 != str_inp2) cout
В этом случае будет следующий результат:
Enter the String 1: Python Enter the String 2: Python Strings are equal
Заключение
В этой статье мы рассмотрели различные способы сравнения строк в языке C++.
Больше информации о C++ вы найдете в официальной документации.
Какая функция корректно сравнивает две подстроки
Операции над строками.
Свойства строки в PHP :
- Строка может содержать любые символы.
- Строка может содержать произвольное количество символов. Длина строки ограничивается только объемом оперативной памяти, что позволяет читать в строку целые файлы и работать с ними, как с обыкновенными строками, например сравнивать.
Для конкатенации (присоединения строк) используется оператор «.» (точка). Пример конкатенации строк:
$c = $a.$b; // число + число
echo «$c\n»; // выведет 2010
$c = $a.$d; // число + строка
echo «$c\n»; // выведет 20 Hello
В PHP операнды сравниваются как строки, только в том случае, если они — строки. В противном случае они сравниваются, как числа. При этом любая строка, которую интерпретатору не удается перевести в число, будет восприниматься, как 0.
Лучше всего для сравнения использовать = = = (тройной оператор равенства — оператор эквивалентности). Он всегда позволяет производить корректное сравнение, т.к. он сравнивает величины и по значению, и по типу.
Функция strlen() возвращает длину строки, то есть количество символов, которое содержит строка.
echo strlen ($a); // выведет5
Функция strpos() ищет подстроку в строке. Функции нужно передать три параметра:
- строку, в которой ищем подстроку.
- подстроку.
- позицию, начиная с которой происходит поиск. Данный параметр необязательный и по умолчанию равен 0.
Если строка не найдена, функция возвращает false, в противном случае — номер позиции, с которой начинается вхождение подстроки в строку:
echo strpos(«Hello», «el»); // выведет 1
Функция substr (string $str, int $from, int $lenght) возвращает заданный участок строки, то есть подстроку. Возвращается подстрока строки $str, начиная с позиции $from длины $length. Если параметр $from будет отрицательным, то отсчет подстроки будет производиться с конца строки, а не с начала. Параметр $length является необязательным.
echo substr ($str, 1, 1); // выведет o
echo substr ($str, -1, 1); // выведет k
Функция strcmp ($str1, $str2) сравнивает две строки и возвращает следующие значения:
0, если строки равны;
1, если строка $str1 лексикографически больше $str2 ;
-1, если строка $str 1 «меньше» $str2.
Функция strasecmp (sstring $str1, string $str2) сравнивает две строки без учета регистра символов, то есть, строки BOOK, BOOK и book для этой функции равны.
Функция str_replace ($str1, $str2, $source) заменяет в строке $source (которая в процессе работы функции не изменяется) все вхождения подстроки $str1 на подстроку $str2 и возвращает результат в виде новой строки.
Пример замены символов новой строки \n на тэг
:
$str = str_replace («\n», «
«, $str);
Функция WordWrap() оказывается очень полезной, когда нужно отформатировать текст письма перед его отправкой. Данная функция разбивает текст письма на строки, завершая каждую символом разрыва строки(по умолчанию \n ). В каждой строке должно быть не более 75 символов (но можно указать и другое их количество). Например:
$s = » Очень длинный блок текста, который нужно разбить на части перед отправкой адресату «;
// разбиваем по 15 символов
$s = WordWrap ($s, 15, «\n»);
Функция strip_tags() . Данная функция удаляет из строки все HTML — тэги:
Список тэгов, которые не стоит удалять, можно указать их при вызове функции:
Обратиться к любому символу строки можно по его индексу:
echo $str[0]; // выведет В
Функция chr (int $code) возвращает строку, состоящую из символа с кодом $code , а функция ord ($char) — код символа $char:
echo chr (75); // выведет K
echo ord (‘A’); // выведет 65 — код буквы A
Для перевода символов в нижний регистр используется функция strtolower(), а в верхний — strtoupper():
$str = strtolower ($str);
$str = strtoupper ($str);
При изменении регистра русских букв могут возникнуть проблемы, избежать которых поможет правильная настройка локали. Локалью называется совокупность настроек системы, таких как формат даты и времени, язык, кодировка. Для установки локали используется функция SetLocale() , которой следует передать два параметра — категорию устанавливаемых параметров и локаль. Категория может быть следующей:
- LC_TYPE — используется для установки локали перевода символов нижний/верхний регистры.
- LC_NUMERIC — используется для установки локали для функции форматирования дробных чисел.
- LC_TIME — помогает настроить форматированный вывод даты и времени.
- LC_ALL — устанавливает все вышеперечисленные режимы.
Любая локаль, установленная в системе, имеет свое уникальное имя, по которому можно к ней обратиться. Категория LC_TYPE устанавливает локаль для преобразования символов. Имя активизированной локали для катагории LC_TYPE содержится в элементе с ключом LAND массива GLOBALS (эта переменная окружения LAND ). В некоторых случаях — это ru_RU.koi8 . Для корректного преобразования символов нужно выполнить функцию:
SetLocal (‘LC_TYPE’, ‘ru_RU.koi8’);
После приема параметров (например при заполнении формы), прежде чем приступить к их обработке, нужно преобразовать значения параметров (удалить лишние пробелы). Пробельными символами являются символы » «, \n, \r, \t.
Функция trim() удаляет пробельные символы в начале и в конце строки, например:
$s = trim ($s); // $s = «string»
Кроме функции trim() можно использовать функции ltrim() и chop(). Первая удаляет пробельные символы только в начале строки, вторая — только в конце.
Функция UrlEncode() используется для кодирования данных. Кодирование необходимо для передачи данных через Интернет, содержащих специальные символы национальных алфавитов, например русского языка. При передаче целого файла его необходимо закодировать с помощью функции UrlEncode() .
Пример автоматического формирования ссылки < a href>:
$Param = » Русский текст «;
В следующем листинге приведен пример, демонстрирующий совместную работу функций UrlEncode() и UrlDecode():
$Param = » Русский текст «;
$Param = UrlEncode ($Param);
$Param = UrlDecode ($Param);
Для вывода кавычек и наклонной черты необходимо использовать цитирование, то есть, запись этих символов через наклонную черту:
Для добавления слэшей используется функция AddSlashes (string $str), а для удаления — StripSlashes (atring $str).
Обе функции возвращают модифицированную строку и не изменяют исходную.
Функция HtmlSpecialChars (string $str) заменяет специальные символы (кавычки, «больше», «меньше» и другие) на их HTML — эквиваленты, для того, чтобы на Web — странице они выглядели сами собой. Например при использовании функции HtmlSpecialChars , знак «больше» в коде будет заменен строкой >, а кавычки — ". Пример использования функции HtmlSpecialChars:
$s = HtmlSpecialChars ($s);
В PHP применяется функция convert_cyr_string(), преобразующая русский текст из одной кодировки в другую. Данной функции необходимо передать три параметра:
- Исходную строку.
- Исходную кодировку.
- Требуемую кодировку.
Последние два параметра могут принимать следующие значения:
w -windows-1251;
d или a — x-cp866;
m — x-mac-cyrillic;
i — iso8859-5.
Пример использования функции convert_cyr_string():
// Преобразование слова «Привет» из кодировки koi8-r в windows-1251
echo convert_cyr_string (» Привет «, «k», «w»); // выведет «оПХБЕР»
Функция md5() кодирует строку, используя алгоритм MD5 (Message Digest Algorithm). Вероятность того, что две разные строки будут иметь одинаковый хэш — код, стремится к нулю, а это позволяет эффективно использовать данную функцию для шифрования паролей. Зашифрованное с его помощью сообщение невозможно расшифровать — для алгоритма MD5 не существует алгоритма дешифровки. Для проверки подлинности пароля нужно зашифровать пароль заново и сравнить зашифрованные строки: если они равны, значит пароль правильный. Например:
if (md5 ($a) === md5 ($b)) echo «1: пароль правильный «;
if (md5 ($a) === md5 ($c)) echo «2: пароль правильный «;
Сценарий выведет только первое сообщение, поскольку строки (значит, и их хэш — коды) равны. Рекомендация по использованию этой функции:
- Пароль не должен храниться в сценарии, тем более в открытом виде. пароль нужно хранить в зашифрованном виде в базе данных или в каком-нибудь файле на диске.
- Введенный пользователем пароль должен зашифровываться и сравниваться уже с зашифрованной строкой, которая прочитана из файла или базы данных.
Кроме функции md5() можно использовать функцию crypt() , которая реализует алгоритм DES , но данный алгоритм менее эффективен, поэтому для серьезных проектов не применяется.
Функция crc32 () используется для вычисления 32 — битной контрольной суммы строки. Данная функция пригодна для регистрации программного продукта через Internet , является стандартной, и менее рекомендуема для серьезных проектов.
Нечёткое сравнение строк: пойми меня, если сможешь

Привет!
На естественном языке сказать об одном и том же факте можно бесконечным числом способов. Можно переставлять слова местами, заменять их на синонимы, склонять по падежам (если говорим о языке с падежами) и тд.
Необходимость определять схожесть двух фраз возникла при решении одной небольшой практической задачи. Я не использовал машинное обучение, не вил нейронные сети, но использовал простые метрики и собранную статистику для калибровки коэффициентов.
Результатом работы, описанием процесса, кодом на git’е готов поделиться с вами.
Итак, кратко задачу можно озвучить так: «С определенной периодичностью из различных источников приходят актуальные новости. Необходимо фильтровать их таким образом, чтобы на выходе не было двух новостей об одном и том же факте.»
Предупреждение: в статье присутствуют заголовки реальных новостей. Я отношусь к ним исключительно как к рабочему материалу, не представляю какую-либо точку зрения на политическую или экономическую ситуацию в какой бы то ни было стране.
Ограничения задачи
Задача имеет прикладной характер, необходимо задать ограничения:
- Каждая новость состоит из заголовка и тела (содержания).
- Заголовок — это осмысленное предложение на естественном языке, по которому человек может понять суть новости.
- Заголовок имеет длину не более 100 символов. Он может состоять из любых символов, включая цифры, пунктуацию и спец.символов.
- Максимальное количество новых новостей, которые могут появиться в промежуток 5 минут — 20 штук.
- Новую новость необходимо сравнивать со всеми новостями, которые приходили за последние сутки.
Примеры заголовков
16; Правительство внесло изменения в программу развития Курил
18; Кабмин увеличил финансирование федеральной программы развития Курил
19; Правительство увеличило финансирование программы развития Курил
6; Инженеры стали самыми востребованными на рынке труда
12; Названы самые востребованные в России профессии
20; Стали известны самые востребованные профессии в России
26; Инженеры признаны самыми востребованными на рынке труда в РФ
32; Инженеры стали самыми востребованными на рынке труда РФ в сентябре
51; Названы самые востребованные профессии в России
53; Минтруд назвал самые востребованные профессии в России
25; Сбербанк с 16 октября снижает ставки по потребительским кредитам
31; Сбербанк снизил процентные ставки по ряду кредитов
37; Сбербанк снизил ставки по ряду кредитов
0; В России выпустят собственную криптовалюту — крипторубль
5; Россия срочно создает крипторубль
27; В России займутся выпуском крипторубля
35; В России создадут свою криптовалюту
36; Россия начнет выпускать крипторубли
42; Россия выпустит собственную криптовалюту – крипторубль
Способы нечёткого сравнения строк
Опишу несколько методов для решения задачи определения степени схожести двух строк.
Расстояние Левенштейна
Возвращает число, которое показывает сколько нужно сделать операций (вставка, удаление или замена) для того, чтобы превратить одну строку в другую.
Свойства: простая реализация; зависимость от порядка слов; на выходе число; которое надо с чем-то сравнить.
Алгоритм шинглов
Разбивает тексты на шинглы (англ. — чешуйки), т.е цепочки по 10 слов (с пересечениями), применив к шинглам хеш-функции получает матрицы, которые и сравнивает между собой.
Свойства: чтобы реализовать алгоритм надо подробно изучать мат.часть; работает на больших текстах; нет зависимости от порядка предложений.
Коэффициент Жаккара (частное — коэф. Танимото)
Вычисляет коэффициент по формуле:
здесь a — количество символов в первой строке, b — количество символов во второй строке, c — количество совпадающих символов.
Свойства: прост в реализации; низкая точность, так как «abc» и «bca» для него одно и то же.
Комбинированных подход
Каждый из приведенных алгоритмов обладает критическими для решаемой задачи недостатками. В процессе работы было реализовано вычисление расстояния Левенштейна и коэффициента Танимото, но, как и ожидалось, они показали плохие результаты.
Эмпирическими рассуждениями комбинированный подход сводится к следующим шагам.
Нормализация сравниваемых предложений
Строки переводятся в нижний регистр, удаляются все символы, отличные от букв, цифр и пробела.
Нормализация предложений
////// Приводит предложение к нормальному виду: /// - в нижнем регистре /// - удалены не буквы и не цифры /// /// Предложение. ///Нормализованное предложение. private string NormalizeSentence(string sentence) < var resultContainer = new StringBuilder(100); var lowerSentece = sentence.ToLower(); foreach (var c in lowerSentece) < if (IsNormalChar(c)) < resultContainer.Append(c); >> return resultContainer.ToString(); > ////// Возвращает признак подходящего символа. /// /// Символ. ///True - если символ буква или цифра или пробел, False - иначе. private bool IsNormalChar(char c)
Выделение слов
Словами считаются все последовательности символов без пробелов, которые имеют длину >= 3. Этим самым удаляются почти все предлоги, союзы и тд. — в какой степени это можно отнести к продолжению нормализации.
Выделение слов
/// /// Разбивает предложение на слова. /// /// Предложение. /// Набор слов. private string[] GetTokens(string sentence) < var tokens = new List(); var words = sentence.Split(' '); foreach (var word in words) < if (word.Length >= MinWordLength) < tokens.Add(word); >> return tokens.ToArray(); >
Сравнение слов по подстрокам
Здесь применяется коэффициент Танимото, но не к символам, а к кортежам из подряд идущих символов, причем кортежи составляются с нахлестом.
Нечеткое сравнение слов
////// Возвращает результат нечеткого сравнения слов. /// /// Первое слово. /// Второе слово. ///Результат нечеткого сравения слов. private bool IsTokensFuzzyEqual(string firstToken, string secondToken) < var equalSubtokensCount = 0; var usedTokens = new bool[secondToken.Length - SubtokenLength + 1]; for (var i = 0; i < firstToken.Length - SubtokenLength + 1; ++i) < var subtokenFirst = firstToken.Substring(i, SubtokenLength); for (var j = 0; j < secondToken.Length - SubtokenLength + 1; ++j) < if (!usedTokens[j]) < var subtokenSecond = secondToken.Substring(j, SubtokenLength); if (subtokenFirst.Equals(subtokenSecond)) < equalSubtokensCount++; usedTokens[j] = true; break; >> > > var subtokenFirstCount = firstToken.Length - SubtokenLength + 1; var subtokenSecondCount = secondToken.Length - SubtokenLength + 1; var tanimoto = (1.0 * equalSubtokensCount) / (subtokenFirstCount + subtokenSecondCount - equalSubtokensCount); return ThresholdWord
Применение коэффициента Танимото к заголовку
Мы знаем сколько всего слов в каждом из предложений, знаем количество «нечётко совпадающих» слов и применяем к этому знакомую формулу.
Нечеткое сравнение предложений
/// /// Вычисляет значение нечеткого сравнения предложений. /// /// Первое предложение. /// Второе предложение. /// Результат нечеткого сравнения предложений. public double CalculateFuzzyEqualValue(string first, string second) < if (string.IsNullOrWhiteSpace(first) && string.IsNullOrWhiteSpace(second)) < return 1.0; >if (string.IsNullOrWhiteSpace(first) || string.IsNullOrWhiteSpace(second)) < return 0.0; >var normalizedFirst = NormalizeSentence(first); var normalizedSecond = NormalizeSentence(second); var tokensFirst = GetTokens(normalizedFirst); var tokensSecond = GetTokens(normalizedSecond); var fuzzyEqualsTokens = GetFuzzyEqualsTokens(tokensFirst, tokensSecond); var equalsCount = fuzzyEqualsTokens.Length; var firstCount = tokensFirst.Length; var secondCount = tokensSecond.Length; var resultValue = (1.0 * equalsCount) / (firstCount + secondCount - equalsCount); return resultValue; > /// /// Возвращает эквивалентные слова из двух наборов. /// /// Слова из первого предложения. /// Слова из второго набора предложений. /// Набор эквивалентных слов. private string[] GetFuzzyEqualsTokens(string[] tokensFirst, string[] tokensSecond) < var equalsTokens = new List(); var usedToken = new bool[tokensSecond.Length]; for (var i = 0; i < tokensFirst.Length; ++i) < for (var j = 0; j < tokensSecond.Length; ++j) < if (!usedToken[j]) < if (IsTokensFuzzyEqual(tokensFirst[i], tokensSecond[j])) < equalsTokens.Add(tokensFirst[i]); usedToken[j] = true; break; >> > > return equalsTokens.ToArray(); >
Алгоритм был протестирован на сотнях заголовков в течении нескольких дней, результаты его работы визуально оказались вполне приемлемыми, но надо было оптимально подобрать следующие коэффициенты:
ThresholdSentence — порог принятия нечеткой эквивалентности всего предложения;
ThresholdWord — порог принятия нечеткой эквивалентности между двумя словами;
SubtokenLength — размер подстроки при сравнении двух слов (от 1 до MinWordLength)
Оценка качества работы алгоритмы
Для оценки качества работы были выделены 100 различных заголовков новостей, которые приходили друг за другом. Далее была размечена квадратная матрица 100×100, где я поставил 0, если заголовки были на разные темы и 1, если темы совпадали. Понимаю, что выборка небольшая и, возможно, не очень точно будет демонстрировать точность работы алгоритма, но меня на большее не хватило.
Теперь, когда есть образец, с которым можно сравнивать выход алгоритма, будем оценивать точность простой формулой — отношением правильных ответов к общему числу сравнений. Кроме того, как метрику, можно оценивать число ложных срабатываний.
Наилучшие результаты c точность 87% и числом ложных срабатываний 3% получаются при следующих параметрах: ThresholdSentence = 0.25, ThresholdWord = 0.45, SubtokenLength = 2;

Сравнение результатов работы алгоритма с моделью
Трактовать результаты можно так:
Наилучшая точность и наименьшее число ошибок получается, если при сравнении слов считать длину подстрок равной 2 символам, при этом должно быть отношение количества совпадающих подстрок к количеству несовпадающих большим или равным 0.45, а два заголовка будут эквивалентными, если не менее четверти слов совпадали.
Если учитывать введенные ограничения, вполне корректные результаты. Конечно, искусственно можно придумать сколько угодно вариантов, на которых появятся ложные срабатывания.
Реальный пример ложного срабатывания
ВТБ снизил минимальную ставку по кредитам наличными
Сбербанк снизил ставки по ряду кредитов
Заключение
Истоки этой задачи лежат в том, что мне понадобилось организовать себе оперативную доставку актуальных новостей. Источники информации — СМИ, которые я постоянно читаю, сидя в интернете, теряя при этом уйму времени, отвлекаясь на ненужную информацию, лишние переходы по ссылкам. В результате родились несколько небольших каналов telegram и групп в контакте. Если вдруг кому-то будет интересно, ссылки есть в описании моего профиля.
Готовая реализация алгоритмы в виде библиотеки: SentencesFuzzyComparison.
- программирование
- сравнение строк
- нечеткое сравнение
- алгоритмы