Convert string to title case with JavaScript

后端 未结 30 2969
夕颜
夕颜 2020-11-21 06:40

Is there a simple way to convert a string to title case? E.g. john smith becomes John Smith. I\'m not looking for something complicated like John R

30条回答
  •  执笔经年
    2020-11-21 07:29

    I wanted to add my own answer as I needed a robust toTitleCase function that takes into account grammar rules listed here (Google recommended article). There are various rules that depend on the length of the input string. Below is the function + unit tests.

    The function also consolidates whitespace and removes special characters (modify regex for your needs)

    toTitleCase Function

    const toTitleCase = (str) => {
      const articles = ['a', 'an', 'the'];
      const conjunctions = ['for', 'and', 'nor', 'but', 'or', 'yet', 'so'];
      const prepositions = [
        'with', 'at', 'from', 'into','upon', 'of', 'to', 'in', 'for',
        'on', 'by', 'like', 'over', 'plus', 'but', 'up', 'down', 'off', 'near'
      ];
    
      // The list of spacial characters can be tweaked here
      const replaceCharsWithSpace = (str) => str.replace(/[^0-9a-z&/\\]/gi, ' ').replace(/(\s\s+)/gi, ' ');
      const capitalizeFirstLetter = (str) => str.charAt(0).toUpperCase() + str.substr(1);
      const normalizeStr = (str) => str.toLowerCase().trim();
      const shouldCapitalize = (word, fullWordList, posWithinStr) => {
        if ((posWithinStr == 0) || (posWithinStr == fullWordList.length - 1)) {
          return true;
        }
    
        return !(articles.includes(word) || conjunctions.includes(word) || prepositions.includes(word));
      }
    
      str = replaceCharsWithSpace(str);
      str = normalizeStr(str);
    
      let words = str.split(' ');
      if (words.length <= 2) { // Strings less than 3 words long should always have first words capitalized
        words = words.map(w => capitalizeFirstLetter(w));
      }
      else {
        for (let i = 0; i < words.length; i++) {
          words[i] = (shouldCapitalize(words[i], words, i) ? capitalizeFirstLetter(words[i], words, i) : words[i]);
        }
      }
    
      return words.join(' ');
    }
    

    Unit Tests to Ensure Correctness

    import { expect } from 'chai';
    import { toTitleCase } from '../../src/lib/stringHelper';
    
    describe('toTitleCase', () => {
      it('Capitalizes first letter of each word irrespective of articles, conjunctions or prepositions if string is no greater than two words long', function(){
        expect(toTitleCase('the dog')).to.equal('The Dog'); // Capitalize articles when only two words long
        expect(toTitleCase('for all')).to.equal('For All'); // Capitalize conjunctions when only two words long
        expect(toTitleCase('with cats')).to.equal('With Cats'); // Capitalize prepositions when only two words long
      });
    
      it('Always capitalize first and last words in a string irrespective of articles, conjunctions or prepositions', function(){
        expect(toTitleCase('the beautiful dog')).to.equal('The Beautiful Dog');
        expect(toTitleCase('for all the deadly ninjas, be it so')).to.equal('For All the Deadly Ninjas Be It So');
        expect(toTitleCase('with cats and dogs we are near')).to.equal('With Cats and Dogs We Are Near');
      });
    
      it('Replace special characters with space', function(){
        expect(toTitleCase('[wolves & lions]: be careful')).to.equal('Wolves & Lions Be Careful');
        expect(toTitleCase('wolves & lions, be careful')).to.equal('Wolves & Lions Be Careful');
      });
    
      it('Trim whitespace at beginning and end', function(){
        expect(toTitleCase(' mario & Luigi superstar saga ')).to.equal('Mario & Luigi Superstar Saga');
      });
    
      it('articles, conjunctions and prepositions should not be capitalized in strings of 3+ words', function(){
        expect(toTitleCase('The wolf and the lion: a tale of two like animals')).to.equal('The Wolf and the Lion a Tale of Two like Animals');
        expect(toTitleCase('the  three Musketeers  And plus ')).to.equal('The Three Musketeers and Plus');
      });
    });
    

    Please note that I am removing quite a bit of special characters from the strings provided. You will need to tweak the regex to address the requirements of your project.

提交回复
热议问题