Преобразование строки текста с помощью JavaScript

#javascript #regex #sentencecase

#javascript #регулярное выражение #sentencecase

Вопрос:

Я работаю над кодом для преобразования строки текста в регистр предложений, который также сохранит сокращения. Я изучал похожие сообщения в StackOverflow, однако я не смог найти тот, который соответствует моим требованиям.

Я уже добился преобразования сокращений и первой буквы в предложении. тем не менее, я столкнулся с другими проблемами, такими как некоторые буквы в предложении по-прежнему в верхнем регистре, особенно тексты в двойных кавычках и после них (» «) и тексты в формате camelcase.

Ниже приведен код, над которым я сейчас работаю, мне нужен кто-то, кто поможет мне оптимизировать код и устранить проблемы.

 String.prototype.toSentenceCase = function() {
  var i, j, str, lowers, uppers;
  str = this.replace(/(^w{1}|.s*w{1})/gi, function(txt) {
    return txt.charAt(0).toUpperCase()   txt.substr(1).toLowerCase();
  });

  
  // Certain words such as initialisms or acronyms should be left uppercase
  uppers = ['Id', 'Tv', 'Nasa', 'Acronyms'];
  for (i = 0, j = uppers.length; i < j; i  )
    str = str.replace(new RegExp('\b'   uppers[i]   '\b', 'g'),
      uppers[i].toUpperCase());

 // To remove Special caharacters like ':' and '?'
    str = str.replace(/[""]/g,'');
    str = str.replace(/[?]/g,'');
    str = str.replace(/[:]/g,' - ');

return str;
}
 

Ввод: поиграйте: это «строка» текста, которую необходимо преобразовать в регистр предложений, в то же время сохраняя сокращения, как это похоже на Nasa.

Текущий вывод: поиграйте — это строка текста, которую необходимо преобразовать в регистр предложений, в то же время сохраняя СОКРАЩЕНИЯ, как это похоже на NASA.

Ожидаемый результат: поиграйте — это строка текста, которую необходимо преобразовать в регистр предложений, в то же время сохраняя СОКРАЩЕНИЯ, как это похоже на NASA.

Ответ №1:

Вот работоспособная версия исходного кода (я немного изменил входную строку):

 String.prototype.toSentenceCase = function() {
  var i, j, str, lowers, uppers;
  str = this.replace(/(^w{1}|.s*w{1})/gi, function(txt) {
    return txt.charAt(0).toUpperCase()   txt.substr(1).toLowerCase();
  });

  
  // Certain words such as initialisms or acronyms should be left uppercase
  uppers = ['Id', 'Tv', 'Nasa', 'Acronyms'];
  for (i = 0, j = uppers.length; i < j; i  )
    str = str.replace(new RegExp('\b'   uppers[i]   '\b', 'g'),
      uppers[i].toUpperCase());

 // To remove Special caharacters like ':' and '?'
    str = str.replace(/[""]/g,'');
    str = str.replace(/[?]/g,'');
    str = str.replace(/[:]/g,' - ');

return str;
}

const input = `play around: This is a "String" Of text, which needs to be cONVERTED to Sentence Case at the same time keeping the Acronyms as it is like Nasa. another sentence. "third" sentence starting with a quote.`
const result = input.toSentenceCase()
console.log(result) 


Я столкнулся с другими проблемами, такими как некоторые буквы в предложении все еще в верхнем регистре, особенно тексты в двойных кавычках и после них (» «) и тексты в формате camelcase.

Некоторые буквы остаются прописными, потому что вы нигде не вызываете .toLowerCase() в своем коде. Ожидайте в начале, но это регулярное выражение предназначено только для начальных букв предложений, а не для других букв.

Может быть полезно сначала ввести все буквы в нижнем регистре, а затем прописные некоторые буквы (сокращения и начальные буквы предложений). Итак, давайте вызовем .toLowerCase() в начале:

 String.prototype.toSentenceCase = function() {
  var i, j, str, lowers, uppers;

  str = this.toLowerCase();

  // ...

  return str;
}
 

Далее, давайте посмотрим на это регулярное выражение:

 /(^w{1}|.s*w{1})/gi
 

Круглые скобки не нужны, поскольку группа захвата не используется в функции replacer . {1} Кванторы также не нужны, поскольку по умолчанию w соответствует только одному символу. Таким образом, мы можем упростить регулярное выражение следующим образом:

 /^w|.s*w/gi
 

Это регулярное выражение находит два совпадения из входной строки:

  • p
  • . a

Оба совпадения содержат только одну букву ( w ) , поэтому в функции replacer мы можем безопасно вызывать txt.toUpperCase() вместо текущего более сложное выражение ( txt.charAt(0).toUpperCase() txt.substr(1).toLowerCase() ) . Мы также можем использовать функцию со стрелкой:

 String.prototype.toSentenceCase = function() {
  var i, j, str, lowers, uppers;

  str = this.toLowerCase();

  str = str.replace(/^w|.s*w/gi, (txt) => txt.toUpperCase());

  // ...

  return str;
}
 

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

Давайте также упростим и объединим регулярные выражения:

 // Before
str = str.replace(/[""]/g,'');
str = str.replace(/[?]/g,'');
str = str.replace(/[:]/g,' - ');

// After
str = str.replace(/["?]/g,'');
str = str.replace(/:/g,' - ');
 

Итак:

 String.prototype.toSentenceCase = function() {
  var i, j, str, lowers, uppers;

  str = this;

  str = str.toLowerCase();

  str = str.replace(/["?]/g,'');
  str = str.replace(/:/g,' - ');

  str = str.replace(/^w|.s*w/gi, (txt) => txt.toUpperCase());

  // ...

  return str;
}
 

Теперь начальная буква третьего предложения правильно прописана. Это потому, что, когда мы вводим начальные буквы в верхнем регистре, третье предложение больше не начинается с кавычки (потому что мы удалили кавычку).

Что осталось, так это прописные сокращения. В вашем регулярном выражении вы, вероятно, захотите также использовать i флаг для совпадений без учета регистра.

Вместо использования for цикла можно использовать одно регулярное выражение для поиска всех совпадений и ввода их в верхний регистр. Это также позволяет нам избавиться от большинства переменных. Вот так:

 String.prototype.toSentenceCase = function() {
  var str;

  str = this;

  str = str.toLowerCase();

  str = str.replace(/["?]/g,'');
  str = str.replace(/:/g,' - ');

  str = str.replace(/^w|.s*w/gi, (txt) => txt.toUpperCase());

  str = str.replace(/b(id|tv|nasa|acronyms)b/gi, (txt) => txt.toUpperCase());

  return str;
}
 

И, похоже, теперь мы получаем правильные результаты!

Однако есть еще три вещи:

  1. Вместо создания и str изменения переменной мы можем изменять this и связывать вызовы методов.
  2. Возможно, имеет смысл переименовать txt переменные в match переменные, поскольку они совпадают с регулярными выражениями.
  3. Изменение прототипа встроенного объекта — плохая идея. Создание новой функции — лучшая идея.

Вот окончательный код:

 function convertToSentenceCase(str) {
  return str
    .toLowerCase()
    .replace(/["?]/g, '')
    .replace(/:/g, ' - ')
    .replace(/^w|.s*w/gi, (match) => match.toUpperCase())
    .replace(/b(id|tv|nasa|acronyms)b/gi, (match) => match.toUpperCase())
}

const input = `play around: This is a "String" Of text, which needs to be cONVERTED to Sentence Case at the same time keeping the Acronyms as it is like Nasa. another sentence. "third" sentence starting with a quote.`
const result = convertToSentenceCase(input)
console.log(result) 

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

1. Большое вам спасибо за то, что объяснили это и исправили это для меня. Я ценю это. не могли бы вы также посоветовать мне, как вызвать это в «классе» или «идентификаторе»?

2. Что вы имеете в виду под этим?

3. Я использую этот скрипт на веб-странице, поэтому он должен применяться для определенного класса, идентификатора, DIV или P (абзаца)

4. первоначальный сценарий, который я опубликовал, я использовал для вызова его по документу. querySelectorAll(‘.предложение’) . forEach(el => el.textContent = el.textContent. toSentenceCase()); где «.sentence» — это имя класса, поэтому оно применяется к определенным элементам с этим именем класса.

5. el.textContent.toSentenceCase() не работает, потому что мы String.prototype больше не расширяем (потому что изменение прототипа встроенного объекта было бы плохой практикой). Мы создали обычную функцию, поэтому вы можете вызывать convertToSentenceCase(el.textContent) вместо нее. Итак: document.querySelectorAll('.sentence').forEach(el => { el.textContent = convertToSentenceCase(el.textContent) }) . Помогает ли это?