JavaScript | Как найти самое длинное слово в строке?

JavaScript | Как найти самое длинное слово в строке?

Введение

Чтобы решить данную задачу, предлагаю сначала определиться, что мы будем считать словом.

Пусть в нашем случае словом будет последовательность кириллических символов, которые следуют друг за другом без разделения на какие-либо другие символы. Это 33 строчные буквы русского алфавита + 33 заглавные буквы русского алфавита.

 

Видео

 

Зачем нужно искать самое длинное слово в строке?

Предположим у вас есть сайт, на котором ваши пользователи могут создавать страницы с контентом. Однажды 100% возникнет ситуация, когда «нехорошие пользователи» начнут публиковать слова в предложениях без пробелов и разделителей.

  • Это может быть сделано неумышленно — человек просто забыл разделить два слова между собой. Частая ситуация при редактировании контента.
  • Это может быть сделано специально — чтобы навредить репутации проекта. Ваш сайт может быть взломан конкурентом. Чтобы вы не сразу заметили о проблеме можно начать пакостить по чуть-чуть, чтобы все ваши дампы баз данных уже не содержали правильного контента. У вас потихоньку начнёт падать посещаемость сайта и вы не сразу заметите проблему.

С подобными проблемами нужно разбираться. В вашей системе управления контентом должны быть инструменты, которые будут отслеживать подобные проблемы. А далее уже вам решать каким образом вы будете исправлять проблемы.

 

 

Решение

Для работы со строками лучше всего использовать регулярные выражения (RegExp) и их шаблоны сопоставления со строками (Pattern).

 

Как мы обозначим русский алфавит в регулярном выражении?

Это можно сделать при помощи синтаксиса Атом и его производства «Класс Символа». В стандарте ECMAScript это производство называется CharacterClass.

[А-яЁё]

Мы отдельно указываем букву «Ё» т.к. она не находится в одной последовательности символьных кодов таблицы ASCII. Один символ из русских букв мы обозначили — это одна пара квадратных скобок.

 

Как найти самую длинную последовательность из русских символов?

Для решения этого вопроса нам нужно обратиться к синтаксису Терм и его производства «Атом Квантификатор». В стандарте ECMAScript это производство называется Atom Quantifier. Отдельный атом у нас уже есть. Теперь нам нужно добавить только Квантификатор.

Мы будем искать самое длинное количество повторений нашего Класса Символа. За это отвечает префикс квантификатора, который обозначается символом плюс «+«. Он ищет повторения того что слева от него, от 1 до бесконечности раз.

[А-яЁё]+

Теперь нам нужно положить этот шаблон регулярного выражения внутрь литералов RegExp, которые обозначаются двумя косыми линиями.

/[А-яЁё]+/

Чтобы отыскать сопоставление по всей строке, нам нужно использовать глобальный флаг — «g»

/[А-яЁё]+/g

 

В каком виде получить результат поиска?

Может сложиться такая ситуация, когда в строке будет несколько последовательностей символов одинаковых по длине, но разных по смыслу. Их тоже нужно видеть. Как это сделать?

Мы можем воспользоваться методом RegExp.prototype [ @@match ] ( string ). Он поможет нам получить результаты сопоставлений в виде массива.

/[А-яЁё]+/g[Symbol.match]("НУЖНО_ВВЕСТИ_СТРОКУ")

В качестве альтернативы можно работать с итератором регулярного выражения и выводить в массив структурированные данные всех результатов сопоставления. Получить итератор регулярного выражения можно при помощи метода RegExp.prototype [ @@matchAll ] ( string ).

[.../[А-яЁё]+/g[Symbol.matchAll]("НУЖНО_ВВЕСТИ_СТРОКУ")]

Но таким способом мы получаем больше данных о самих сопоставлениях. В этой задаче они не так важны.

Вызов этой конструкции вернёт нам объект итератора, у которого будет работать только один метод next(). В таком виде он нам не интересен, поэтому мы сразу можем выгружать готовые результаты сопоставления внутрь пустого массива при помощи оператора spread (троеточие).

Сортировка результатов по длине строк сопоставления

Используем метод sort() для массивов. Нам важно перетянуть самые длинные слова в начало массива. Именно поэтому мы используем свойство length для строк массива в качестве маркера сортировки.

/[А-яЁё]+/g[Symbol.match]("НУЖНО_ВВЕСТИ_СТРОКУ").sort((a,b)=>b.length-a.length)

 

Фильтрация результатов по максимальной длине

Теперь нужно отбросить короткие строки из массива и оставить в нём только самые длинные результаты. В этом нам поможет метод filter(), который мы будем вызывать с двумя параметрами.

/[А-яЁё]+/g[Symbol.match]("НУЖНО_ВВЕСТИ_СТРОКУ")
.sort((a,b)=>b.length-a.length)
.filter(i=>{if(x==0){x=i.length};return i.length==x}, x=0)

или

/[А-яЁё]+/g[Symbol.match]("НУЖНО_ВВЕСТИ_СТРОКУ")
.sort((a,b)=>b.length-a.length)
.filter(i=>x==0?x=i.length:i.length==x, x=0);

Вторым параметром в метод filter() мы передаём выражение x=0, которое по сути будет «переключателем на одни раз». С его помощью мы поймаем длину самого первого элемента отсортированного массива. Когда у нас есть самая длинная строка, тогда её длина не может быть равна нулю. Значение ноль — это страховка. Этого достаточно для одного переключения.

В первый вызов коллбека фильтра мы проверим переменную «x» на равенство с нулём x==0. Мы можем использовать условный оператор для возвратов стрелочной функции.

В первый вызов это условие сработает в true и мы выполним присваивание числа с максимальной длиной для переменной «x«. Результат присваивания будет приведён к логическому типу, а значит коллбек отработает в true на первой итерации и вернёт первый элемент в любом случае.

Логика приведения к логическому типу внутри метода filter - JavaScript
Логика приведения к логическому типу внутри метода filter — JavaScript

Мы специально проводили сортировку. Мы точно знаем, что первый элемент самый длинный.

Вызов конструктора Boolean с выражением присваивания - JavaScript
Вызов конструктора Boolean с выражением присваивания — JavaScript

Во второй и последующие вызовы условие будет пробрасывать нас во второй блок условного оператора, в котором мы будем сравнивать длину текущей строки из массива с длиной максимальной строки — с тем, что присвоилось для «x«.

 

Пример

/[А-яЁё]+/g[Symbol.match]("а ааа аа б ккк к ббб").sort((a,b)=>b.length-a.length).filter(i=>x==0?x=i.length:i.length==x, x=0);

["ааа", "ккк", "ббб"]
Пример получения трёх самых длинных слов из строки - JavaScript
Пример получения трёх самых длинных слов из строки — JavaScript

 

Функция

// Функция с защитой
function getBiggestWord(str=""){
   if(str.constructor.name=="String"&&str.length>0)
   return /[А-яЁё]+/g[Symbol.match](str)
   .sort((a,b)=>b.length-a.length)
   .filter(i=>x==0?x=i.length:i.length==x, x=0);
   else return []
}

 

Информационные ссылки

Стандарт ECMAScript — Раздел «23.1.3.8 Array.prototype.filter ( callbackfn [ , thisArg ] )» — https://tc39.es/ecma262/#sec-array.prototype.filter