0

I am trying to correct casing issues due to improper data input (writing in all CAPS, all lower case, or improper unit capitalizations) when returning records from and older DB. I found this solution for converting a string to title case, but I want to add exceptions to it. The original code had an exception to lower case minor words unless they are the first or last word, which I really like, but I want to add an additional exception for another predefined array of words that I have already set the casing for (Initialisms, acronyms, units of measure) that I can add to as we find more exceptions. I know it is not recommended to change a prototype, but I have yet to find another way to make it work like the ‘.toLowerCase()’ method, and I really like being able to make it work like a method and add ‘.toTitleCase()’ after my value like this: {item.name.toTitleCase()}.

Is there a way of accomplishing this without modifying the prototype, but still use it as a method, plus adding an array of exceptions?

Here is what I have:

const casingPreset = ["cm", "DOE", "ft", "ID", "KC", "mm", "TV", "USA"];

String.prototype.toTitleCase = function () {
  var i, j, str, lowers;
  str = this.replace(/([^\W_]+[^\s-]*) */g, (txt) => {
    return txt.charAt(0).toUpperCase() + txt.substring(1).toLowerCase();
  });

  // Words left lowercase unless first or last words in the string
  lowers = ["A", "An", "And", "As", "At", "But", "By", "For", "From", "In", "Into", "Near", "Nor", "Of", "On", "Onto", "Or", "The", "To", "With"];
  for (i = 0, j = lowers.length; i < j; i++)
    str = str.replace(new RegExp("\\s" + lowers[i] + "\\s", "g"), function (txt) {
      return txt.toLowerCase();
    });

  return str;
};

Taking something like this: ‘THE DOE IN THE USA DOESN’T USE THE UNIT CM.’

And returning something like this: “The DOE in the USA Doesn’t Use the Unit cm.’

Of course the example above is nonsense, but give you an idea of what I want to accomplish

kelsny
  • 23,009
  • 3
  • 19
  • 48
Mtullis
  • 117
  • 9

1 Answers1

1

You would have to put it in a function that takes a string as an argument. This parameter effectively replaces "this" in the function.

const casingPreset = ["cm", "DOE", "ft", "ID", "KC", "mm", "TV", "USA"];

function toTitleCase (input) {
  var i, j, str, lowers;
  str = input.replace(/([^\W_]+[^\s-]*) */g, (txt) => {
    return txt.charAt(0).toUpperCase() + txt.substring(1).toLowerCase();
  });

  // Words left lowercase unless first or last words in the string
  lowers = ["A", "An", "And", "As", "At", "But", "By", "For", "From", "In", "Into", "Near", "Nor", "Of", "On", "Onto", "Or", "The", "To", "With"];
  for (i = 0, j = lowers.length; i < j; i++)
    str = str.replace(new RegExp("\\s" + lowers[i] + "\\s", "g"), function (txt) {
      return txt.toLowerCase();
    });

  return str;
};

console.log(toTitleCase("harry potter and the sorceror's stone"));

Or you can extend the native String class and add a method there... but you would have to create a string like new SuperString(...) which is less than ideal.

const casingPreset = ["cm", "DOE", "ft", "ID", "KC", "mm", "TV", "USA"];

class SuperString extends String {
  toTitleCase() {
    var i, j, str, lowers;
    str = this.replace(/([^\W_]+[^\s-]*) */g, (txt) => {
      return txt.charAt(0).toUpperCase() + txt.substring(1).toLowerCase();
    });

    // Words left lowercase unless first or last words in the string
    lowers = ["A", "An", "And", "As", "At", "But", "By", "For", "From", "In", "Into", "Near", "Nor", "Of", "On", "Onto", "Or", "The", "To", "With"];
    for (i = 0, j = lowers.length; i < j; i++)
      str = str.replace(new RegExp("\\s" + lowers[i] + "\\s", "g"), function (txt) {
        return txt.toLowerCase();
      });

    return str;
  }
}

console.log(new SuperString("harry potter and the sorceror's stone").toTitleCase());
kelsny
  • 23,009
  • 3
  • 19
  • 48