如何在JavaScript中检查元音字母?

38
我应该写一个函数,接受一个字符(即长度为1的字符串),并返回true如果它是元音字母,否则返回false。我想出了两个函数,但不知道哪个表现更好,以及我应该选择哪种方式。没有正则表达式的这个函数更简单,但我不确定是否应该尽量避免使用正则表达式?
function isVowel(char) {
  if (char.length == 1) {
    var vowels = new Array("a", "e", "i", "o", "u");
    var isVowel = false;

    for (e in vowels) {
      if (vowels[e] == char) {
        isVowel = true;
      }
    }

    return isVowel;
  }
}

使用正则表达式:

function isVowelRegEx(char) {
  if (char.length == 1) {
    return /[aeiou]/.test(char);
  }
}

3
只是出于好奇,如果字符串长度不为1,你的函数应该返回什么? - Martin Hennings
2
benchmark - Raynos
3
我不确定上下文是什么,但处理不同语言会有问题。例如,在名字Zoë中,你会如何对待字母“ë”?即使它是独立存在的元音字母。您能提供更多信息吗? - T9b
12个回答

55

基准测试

我认为可以放心地说for循环更快。

我承认,就代码而言,正则表达式看起来更简洁。如果这是一个真正的瓶颈,那么使用for循环,否则出于"优雅"的原因,坚持使用正则表达式。

如果您想保持简单,只需使用

function isVowel(c) {
    return ['a', 'e', 'i', 'o', 'u'].indexOf(c.toLowerCase()) !== -1
}

1
在Firefox 4中,indexOf()是最快的。顺便说一句,有一个很酷的基准测试网站可以使用!! - Max
@Max 有趣的是,Firefox 如何优化字符串的索引。 - Raynos
1
在编程中,最好使用显式的 if 语句来检查某个字符是否等于 'a' 或者 'e' 等,这样比使用正则表达式要快得多。但是,火狐浏览器貌似不一样! - Pointy
1
我明白了。它有时比正则表达式快两倍。有趣! :) - Max
1
@Pointy只在crankshaft中存在。在jagermonkey中,字符串索引更加优化,在IE8中索引和表达式则势均力敌。说实话,在这个级别上,您正在为特定的JavaScript引擎进行优化。只需使用简短、可读和易于维护的内容即可。另外,nitro更喜欢索引。不过我没有carakan来测试。 - Raynos
显示剩余2条评论

31

许多答案都可用,对于这种小函数,除非您在短时间内调用它们数十万次,否则速度无关紧要。对我来说,正则表达式是最好的选择,但将其保持在闭包中,以便每次不必重建它:

简单版本:

function vowelTest(s) {
  return (/^[aeiou]$/i).test(s);
}

更高效的版本:

var vowelTest = (function() {
  var re = /^[aeiou]$/i;
  return function(s) {
    return re.test(s);
  }
})();

如果s是单个元音字母(大小写均可),则返回true,否则返回false


请问您能详细说明更高效的版本吗?我运行它,它的功能就像简单版本一样,但是(1)为什么它被认为更有效率?(2)最外层的括号表示什么?乍一看,我会说这是一个返回函数(闭包函数)的函数。最外层的(...)()有影响吗? - thetrystero
我认为这更有效率,因为正则表达式只创建一次并重复使用,而不是每次都创建。括号“()”将函数声明转换为函数表达式,因此可以省略名称。它也可以以!开头,但分组还具有语义,表示“所有这些都属于一起”,而“!”似乎表示“不是某个东西...”。尾随的“()”导致函数被调用,并且可以在关闭“)”内部或外部,许多人更喜欢在内部(再次是语义)。 - RobG
你开始说速度不重要,为什么使用闭包会被认为是一个重要的优化? - José Salgado
@JoséSalgado - 因为有时速度确实很重要。 :-) - RobG

9
循环、数组、正则表达式...这些都是为了什么?其实有更快的方法 :)
function isVowel(char)
{
    return char === 'a' || char === 'e' || char === 'i' || char === 'o' || char === 'u' || false;
}

如果 char 是一个字符串,这将会失败。 - Buhake Sindi
如果char.length > 1,它将返回false,我认为这是正确的。 - Emmerman
1
String.prototype.index在Firefox中比这个更快。而且这个很丑。 - Raynos
@Raynos 不像循环那么丑(对于这个问题):) 是的,也许索引更快。我只是为了好玩和另一种解决方案而发布了这个。 - Emmerman
为什么这个函数以 || false 结尾? - damd
显示剩余2条评论

6
function findVowels(str) {
  return str.match(/[aeiou]/ig);
}

findVowels('abracadabra'); // 'aaaaa'

基本上,它会返回给定字符串中的所有元音字母。

4

个人而言,我会这样定义:

function isVowel( chr ){ return 'aeiou'.indexOf( chr[0].toLowerCase() ) !== -1 }

您也可以使用['a','e','i','o','u']并跳过长度测试,但这样每次调用函数时都会创建一个数组。(虽然有通过闭包模拟此行为的方法,但那些方法阅读起来有点晦涩)


1
正则表达式更好,而且速度不明显变慢/[aeiou]/.text(chr.toLowerCase()) - Raynos

4
这是一个我想出的粗略的 RegExp 函数(未经测试)。
function isVowel(char) {
    return /^[aeiou]$/.test(char.toLowerCase());
}

这意味着,如果 (char.length == 1 && 'aeiou' 包含在 char.toLowerCase() 中),则返回 true

4

我认为以下方法比较全面且实用:

const matches = str.match(/[aeiou]/gi);
return matches ? matches.length : 0;

5
我认为你的匹配代码中有一个拼写错误。const matches = str.match(/[aeiou]/gi); - Zoti

2
function isVowel(char)
{
  if (char.length == 1)
  {
    var vowels = "aeiou";
    var isVowel = vowels.indexOf(char) >= 0 ? true : false;

    return isVowel;
  }
}

基本上它检查元音字母字符串中字符的索引。如果是辅音字母且不在该字符串中,则 indexOf 将返回 -1。


@Raynos,有人可能会争辩,返回undefined是否必要? - Buhake Sindi
@TheEliteGentleman有人可以认为,在长度>1的字符串上使用isVowel是未定义行为,因此应当有效地返回“undefined”。 aa 不是元音字母是什么意思? - Raynos

2

基本上,它会返回给定字符串中的所有元音字母。

function vowels(s) {
  let vowels = ["a", "e", "i", "o", "u"];

  for(let v of s) {
    if(vowels.includes(v))
        console.log(v);
  }
}

1
这是我所使用的方法,在任何给定单词中第一次出现元音字母时,就会跳出循环并返回true。
const vowels = ["a", "e", "i", "o", "u", "y"];

function isVowel(word) {
    let result = false;
    for (let i = 0; i < word.length; i++) {
        if (vowels.includes(word[i])) {
            result = true;
            break;
        }
    }
    return result;

经过测试,似乎 break 是不必要的,但我不是专家,最近才开始学习js,所以我可能错了。 - Yuniac

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接