2

I need to retrieve names from a database, these names can be searched using accented and unaccented vowels, in both ways the response has to return all matched names. The approach I used to solve this problem is a function that replaces the vowels from the searched name with a string that contains both vowels in order to look for both options with a regex method.

How can I optimize this function?

const replaceVowels = fullName => {
    const v = [
        { vocal: "a", replace: "[aá]" },
        { vocal: "e", replace: "[eé]" },
        { vocal: "i", replace: "[ií]" },
        { vocal: "o", replace: "[oó]" },
        { vocal: "u", replace: "[uú]" },
        { vocal: "á", replace: "[aá]" },
        { vocal: "é", replace: "[eé]" },
        { vocal: "í", replace: "[ií]" },
        { vocal: "ó", replace: "[oó]" },
        { vocal: "ú", replace: "[uú]" }
    ];
    for (let i = 0; i < v.length; i++) {
         fullName = fullName.replace(new RegExp(v[i].vocal, "gi"), v[i].replace);
    }
    return { $regex: fullName, $options: "i" };
};
replaceVowels("mayúsculas");
// returns "m[aá]y[uú]sc[uú]l[aá]s"
anibalajt
  • 958
  • 6
  • 12
  • 1
    The output of `replaceVowels("mayúsculas")` is `"m[aá]y[uú]sc[uú]l[aá]s"`, right? – Nathan Hinchey May 25 '18 at 16:03
  • 2
    Possible duplicate of [Remove accents/diacritics in a string in JavaScript](https://stackoverflow.com/questions/990904/remove-accents-diacritics-in-a-string-in-javascript) –  May 25 '18 at 16:04
  • @NathanHinchey yes, exactly. – anibalajt May 25 '18 at 16:05
  • very weird behavior of replace... – Calvin Nunes May 25 '18 at 16:07
  • 1
    Why are the `vocal`s being turned into regular expressions? – Zak May 25 '18 at 16:08
  • @Zak In order to run a find_like in Mongodb – anibalajt May 25 '18 at 16:11
  • 1
    Based on your last comment, is [this what you're looking for?](https://stackoverflow.com/q/7707671/4639281) –  May 25 '18 at 16:21
  • 1
    @anibalajt Are you sure your function does what you think it does? When I try to run it it returns a promise, and when I change it to just be a standard function it returns `"m[a[aá]]y[uú]sc[u[uú]]l[a[aá]]s"` – Nathan Hinchey May 25 '18 at 16:31
  • 1
    @NathanHinchey by async – anibalajt May 25 '18 at 16:36
  • With the latest edit the last line returns `{$regex: "m[a[aá]]y[uú]sc[u[uú]]l[a[aá]]s", $options: "i"}` – Nathan Hinchey May 25 '18 at 16:41
  • 1
    @anibalajt I think instead of doing a regular expression search, you should just normalise (i.e. removed diacritics) the string in your database and normalise the search expression and then do a normal search. – Bergi May 25 '18 at 16:42
  • "*How can I optimize this function?*" - did you mean "How can I fix this function?"? It doesn't seem to do what you want. And start by dropping the unnecessary `async`. – Bergi May 25 '18 at 16:44

2 Answers2

1

A simple (very minor) speed optimization would be to make the vowel list an object, and just go through fullName once. As a bonus, the code works as intended now!

const replaceVowels = fullName => {
  const v = {
    "a": "[aá]",
    "e": "[eé]",
    "i": "[ií]",
    "o": "[oó]",
    "u": "[uú]",
    "á": "[aá]",
    "é": "[eé]",
    "í": "[ií]",
    "ó": "[oó]",
    "ú": "[uú]"
  };
  let output = "";
  for (let i = 0; i < fullName.length; i++) {
    if (v[fullName[i]]){
      output += v[fullName[i]];
    }
    else {
      output += fullName[i];
    }
  }
  return output;
};
replaceVowels("mayúsculas");
// returns "m[aá]y[uú]sc[uú]l[aá]s"
Nathan Hinchey
  • 1,191
  • 9
  • 30
0

For making things more efficient, why not just use a text index in MongoDB - especially as they already have the behaviour you desire?

However, clearing up the earlier answer I gave, you can make the function more compact.

const replaceVowels = fullName => {
  // Patterns to match characters
  // ... that should then be replaced with the pattern
  const v = ["[aá]", "[eé]", "[ií]", "[oó]", "[uú]"];
  
  for (let i = 0; i < v.length; i++) {
    fullName = fullName.replace(new RegExp(v[i], "gi"), v[i]);
  }
  
  return {
    $regex: fullName,
    $options: "i"
  };
};

console.log(replaceVowels("mayúsculas"));
Zak
  • 1,042
  • 6
  • 12