Комментарии 18
В первой задаче берем в качестве примера строку, которая включает в себя emoji и смотрим, как с ней справляются оба ваших решения в сравнении с однострочником:
Это происходит, потому что ваш код не учитывает существование знаков вне BMP, которые кодируются суррогатными парами UTF-16, и адресует не codepoint-ы, а их UTF-16-кодированное представление.
const re = /[^A-Za-zА-Яа-я]/g
const string = 'Моя удивительная строка'
let match, pos = 0, maxLength = 0
while (re.exec(string + '.') !== null) {
maxLength = Math.max(maxLength, re.lastIndex - pos - 1)
pos = re.lastIndex
}
console.log('Длина самого длинного слова:' + maxLength)
Можно ускорить ваше решение, если искать не небуквенные символы, а места переходов от буквенных к небуквенным:
function longest(s) {
const reStart = /(?:\W|^)\w/g;
const reEnd = /\w(?:\W|$)/g;
let inWord = false;
let longest = 0;
let startOffset;
do {
if (!inWord) {
const m = reStart.exec(s);
if (!m) {
return longest;
}
reEnd.lastIndex = reStart.lastIndex - 1;
startOffset = m.index - 2 + m[0].length;
inWord = true;
} else {
const m = reEnd.exec(s);
reStart.lastIndex = reEnd.lastIndex - 1;
longest = Math.max(longest, m.index - startOffset);
inWord = false;
}
} while (true);
};
Можете подсказать хорошие статьи по ним?
/[^A-Za-zА-Яа-я]+/g
но это будет извлекать ненужные участки междусловных знаков как строку, от чего мы вроде как хотели избавиться? :)
И, наверное, лучше использовать классы знаков — ваше выражение аналогично /\W+/g
, но не считается с буквами других алфавитов.
function findLongestWordLength(str) {
let max = 0,
tmp = 0;
for (let idx = str.length - 1; idx >= 0; idx--) {
if (str.charAt(idx) === ' ') {
max = Math.max(max, tmp)
tmp = 0
}
else
tmp++;
}
return Math.max(max, tmp)
}
console.log('Длина самого длинного слова: ' + findLongestWordLength('Моя удивительная строка'))
А Вы уверены, что регулярки в данном случае сэкономят время? Это довольно тяжелый инструмент. Я бы уж тогда сделал вот так
const string = 'Моя удивительная строка';
let pos = 0, max = 0;
for (const idx in string) {
if (string[idx] == ' ' || idx == string.length - 1) {
max = Math.max(max, idx - pos);
pos = idx;
}
}
const l = string[idx]
if ((l < 'A' || l > 'Z') &&
(l < 'a' || l > 'z') &&
(l < 'А' || l > 'Я') &&
(l < 'а' || l > 'я'))
Так да, возможно перебор будет немного быстрей.
Странно, что в примерах на поиск максимума в массивах не используется reduce. На мой взгляд это проще, чем map с… И вообще создавать дополнительные массивы для поиска максимума странно, если можно обойтись итераторами.
Вторая задача не учитывает пунктуацию. Можно сделать так:
Или, как вариант, не абюзить replace и запросить все матчи как-то так:
const allMatches = (s, re) => {
const matches = [];
let m;
while (m = re.exec(s)) {
matches.push(m[0]);
}
return matches;
}
Но мне кажется, что это проще сделать за один проход.
str.split(' ').reduce((acc, item) => {
if(item.length > acc) acc = item.length
return acc
} , 0)
const getLongest = (str) => str.split(' ').sort((a,b) => b.length - a.length)[0]
getLongest('My name is HelloWorld').length
function reverse(str) {
return _reverse(str.matchAll(/./gu));
}
function _reverse(lettersIter) {
const { value, done } = lettersIter.next();
if (done) {
return '';
}
return _reverse(lettersIter) + value[0];
}
function findLongestWordLength(str) {
const wordsIter = str.matchAll(/[^ ]+/gu);
return _findLongestWordLength(wordsIter);
}
function _findLongestWordLength(wordsIter) {
const { value, done } = wordsIter.next();
if (done) {
return 0;
}
return Math.max(value[0].match(/./gu).length, _findLongestWordLength(wordsIter));
}
function largest(arr) {
return arr.map(it => maximum(it[Symbol.iterator]()));
}
function max(a, b) {
return a >= b ? a : b;
}
function maximum(iter) {
const { value, done } = iter.next();
if (done) {
return 0;
}
return max(value, maximum(iter));
}
Решение частых алгоритмических вопросов на JavaScript