Как стать автором
Обновить

Комментарии 18

В первой задаче берем в качестве примера строку, которая включает в себя emoji и смотрим, как с ней справляются оба ваших решения в сравнении с однострочником:


image


Это происходит, потому что ваш код не учитывает существование знаков вне 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 с… И вообще создавать дополнительные массивы для поиска максимума странно, если можно обойтись итераторами.

Вторая задача не учитывает пунктуацию. Можно сделать так:


image


Или, как вариант, не абюзить 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];
}

image




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));
}

image


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));
}

image

Зарегистрируйтесь на Хабре , чтобы оставить комментарий

Публикации

Истории