0

I'm currently working on a fix where there's an existing function that capitalizes each word of the given string. Each value that comes out of that function is later used to validate other logic.

So right now, that function is capitalizing texts in the wrong way. For example internet of things comes out as Internet Of Things and I need it as Internet of Things

This is the function with an adjustment I made, which is basically if the string contains "of" ignore it:

const cleanValue = value
        .replace(/-/g, ' ')
        .split(' ')
        .map((word, i) => {
            return word === 'of' && i != 0 ? word : word[0].toUpperCase() + word.substring(1);
        })
        .join(' ');

But my boss thinks it's a kind of hacky solution and is asking me to look for a better solution, I'm honestly having a hard time trying to fix this in a better way.

Any advice/ideas anyone could provide me on how to improve this?

Thank you!

Marian Klösler
  • 620
  • 8
  • 22
ypdev19
  • 173
  • 2
  • 13
  • This is more of a IR (Information Retrieval) question. Like "teaching" a computer to know when to capitalize something. – Shmack Jan 25 '23 at 23:17
  • 2
    the problem is that you need to define which words are to be the exceptions. For example, we know that _of_ is one of them but what about _the_ (as in Lord of the Rings) ? or _and_ (as in Mac and Cheese) - hopefully you can tell how, the more exceptions you define, the less practical your solution seems to be. – blurfus Jan 25 '23 at 23:19
  • 2
    Ideas: https://stackoverflow.com/a/6475125/271415 – jarmod Jan 25 '23 at 23:34
  • It’s impossible to always be correct when the input has been transformed into a format that loses data. Your solution seems fine as a quick fix – it’s extensible to an array of words that shouldn’t be capitalized, as seen with the `includes` answer – and if you need something genuinely robust then it’ll take more context (e.g. do you want to go as far as trying to understand language?). – Ry- Jan 25 '23 at 23:39
  • Well, the use case behind the logic of that functionality is that will use a specific group of phrases that as far as i know, don't contain any other exception words different to: "of, and, the" to validate other things. So i think with the suggested answers i got what i need, thank you! – ypdev19 Jan 26 '23 at 00:12

3 Answers3

1

If you want to ignore some words then you can change your function like this.

const ignoreWords = ["of", "the", "and"];
const cleanValue = value
        .replace(/-/g, ' ')
        .split(' ')
        .map((word) => {
            return ignoreWords.includes(word.toLowerCase()) ? word : word[0].toUpperCase() + word.substring(1);
        })
        .join(' ');
saroj
  • 121
  • 1
  • 7
1

Not sure I love this idea--and it's not super efficient--but it's flexible enough to accommodate a bunch of arbitrary rules.

You could declare a set of transformers that each have 1) a predicate function that determines whether it handles a particular case, and 2) a function to do the transformation.

The last transformer in the set is the default. Its predicate always returns true, and it does capitalization.

Split the string into words and for each word find a transformer to handle it.

const lowerMiddleWords = ['a', 'at', 'of', 'and', 'the', 'for', 'with'];

const capitalize = (word) => word[0].toUpperCase() + word.substring(1);

const transformers = [
  {
    predicate: (word, index) => index && lowerMiddleWords.includes(word),
    transform: (word) => word,
  },
  {
    predicate: (word, index, phrase) => phrase.includes('hackers'),
    transform: (word) => capitalize(word.replaceAll('e', '3')),
  },
  {
    predicate: () => true,
    transform: capitalize,
  }
]

function transform(string) {
  return string.split(' ').map((word, index) => {
    const transformer = transformers.find((t) => t?.predicate(word, index, string));
    return transformer.transform(word);
  }).join(' ');
}

[
  "internet of things",
  "for the birds",
  "at peace with the world",
  "the good, the bad, and the ugly",
  "capitalize all of the things",
  "leet hackers like threes",
].forEach(str => console.log(transform(str)));
ray
  • 26,557
  • 5
  • 28
  • 27
-2

So here's a javascript solution.

Suppose that you receive a string with name data

const ignoreWords = ["of", "the", "and"]; //used as references other codes from this post

function stringUpperCase(Data){

let ArrayOfStrings = Data.split(" ");
let ArrayUpperCased = [];
    
ArrayOfStrings.map((word) =>{

if(!ignoreWords.includes(word.toLowerCase())){

    ArrayUpperCased.push(word.charAt(0).toUpperCase() + word.slice(1)); //captalize the word
    return;
}
ArrayUpperCased.push(word.toLowerCase());
return ;
    
})

return ArrayUpperCased.join(" ");

}

stringUpperCase("Test Of Text")
// return 'Test of Text'

In this way you can customize the words that you want to ignore and the ones that you want to Uppercase;

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Vicente
  • 26
  • 3
  • 1
    The relevant part of this is the same as the original code, and the rest of it is worse. – Ry- Jan 25 '23 at 23:35
  • so i dont get what he wants, I thinked hi just want a refactored way of do it. – Vicente Jan 25 '23 at 23:49
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jan 27 '23 at 14:53