JavaScript中检查字母数字的最佳方法

188

JSP 中,执行对 INPUT 字段进行字母数字检查的最佳方法是什么?我附上了我的当前代码。

function validateCode() {
    var TCode = document.getElementById("TCode").value;

    for (var i = 0; i < TCode.length; i++) {
        var char1 = TCode.charAt(i);
        var cc = char1.charCodeAt(0);

        if ((cc > 47 && cc < 58) || (cc > 64 && cc < 91) || (cc > 96 && cc < 123)) {
        } else {
            alert("Input is not alphanumeric");
            return false;
        }
    }

    return true;
}


4
取决于你如何定义“最佳”。下面的大多数答案建议使用正则表达式,但其性能比你原来的代码慢得多。我稍微整理了一下你的代码,它实际上表现得非常好。 - Michael Martin-Smucker
15个回答

157

根据提问者的最初倾向,使用str.charCodeAt(i)似乎比正则表达式更快。在我的jsPerf测试中,RegExp选项在Chrome 36中慢了66%(在Firefox 31中稍微慢一些)。

这是原始验证代码的清理版本,它接收一个字符串并返回truefalse

function isAlphaNumeric(str) {
  var code, i, len;

  for (i = 0, len = str.length; i < len; i++) {
    code = str.charCodeAt(i);
    if (!(code > 47 && code < 58) && // numeric (0-9)
        !(code > 64 && code < 91) && // upper alpha (A-Z)
        !(code > 96 && code < 123)) { // lower alpha (a-z)
      return false;
    }
  }
  return true;
};

当然,还有其他的考虑因素,比如可读性。一行正则表达式确实更美观。但如果你严格关注速度,你可能需要考虑这个替代方案。


27
程序员喜欢代码的外表,但你能看到它内在的美。 - Ziggy
有趣的替代方案——我甚至从未想过。我来这里只是想到正则表达式! - Andy
这个答案让你思考并理解了“编程”的含义。我使用了你的思维方式,在我的回答中。 - Oscar Zarrus
6
为什么我们需要在 charCodeAt 中进行字符编码比较?难道我们不能使用字符串字符 (c >= '0' && c <= '9'), (c >= 'a' && c <= 'z'), (c >= 'A' && c <= 'Z') 进行字符串比较吗? - Xitang
我喜欢你的思维方式,性能非常重要。 - mohamed chadad

144
你可以使用该正则表达式 /^[a-z0-9]+$/i,它可以允许字母和数字的输入。参考链接:这里

5
当然,这意味着空字符串 ("") 不应该被匹配。 - zzzzBov
25
ñ 不符合规则,但仍是一个完全有效的 UTF-8 字符。 - Oybek
16
这段代码的含义是:通过正则表达式判断变量TCode是否由大小写字母和数字组成。 - Alex V
4
测试正则表达式似乎比使用charCodeAt()慢得多(在Chrome 36中为66%)。请参见jsPerf我在stackoverflow上的回答 - Michael Martin-Smucker
11
这个正则表达式无法处理某些语言中使用的特殊字符,比如 "ą"、"ź"、"ć" 等。 - Rafał Swacha
显示剩余7条评论

78

使用正则表达式进行检查。

Javascript的正则表达式没有POSIX字符类,因此您必须手动编写字符范围:

if (!input_string.match(/^[0-9a-z]+$/))
  show_error_or_something()

这里的^表示字符串的开头,$表示字符串的结尾,[0-9a-z]+表示一个或多个字符,可以是数字09或小写字母az

有关 JavaScript 正则表达式的更多信息请参见: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions


24
翻译自英文到中文。仅返回翻译后的文本:+1 表示解释基本的正则表达式并链接到指南,而不是给用户一个“魔术字符串”。 - Charles Burns
4
你可以在正则表达式末尾添加'i'来指定不区分大小写,例如"/^[a-z0-9]+$/i",这将涵盖大小写字母。 - LJH

40

您不需要逐个进行操作。只需测试任何一个非字母数字字符即可。如果找到一个,验证失败。

function validateCode(){
    var TCode = document.getElementById('TCode').value;
    if( /[^a-zA-Z0-9]/.test( TCode ) ) {
       alert('Input is not alphanumeric');
       return false;
    }
    return true;     
 }

如果存在至少一个非字母数字的匹配,return false


32

要匹配所有Unicode字母和数字,您可以使用Unicode正则表达式:

const alphanumeric = /^[\p{L}\p{N}]*$/u;

const valid   = "Jòhn꠵Çoe日本語3rd"; // <- these are all letters and numbers
const invalid = "JohnDoe3rd!";

console.log(valid.match(alphanumeric));
console.log(invalid.match(alphanumeric));

在上面的正则表达式中,u标志启用Unicode模式\p{L}代表\p{Letter}\p{N}代表\p{Number}。方括号[]将它们包围在内,是一个普通的字符类,意味着字符必须是字母或数字(在这个上下文中)。*表示“零个或多个”,如果不想允许空字符串,可以将其改为+(一个或多个)。^/$匹配字符串的开头/结尾。

上述方法适用于大多数情况,但可能匹配超出你的需求。你可能不想匹配拉丁文、阿拉伯文、西里尔文等。你可能只想匹配拉丁字母和十进制数字。

const alphanumeric = /^[\p{sc=Latn}\p{Nd}]*$/u;

const valid   = "JòhnÇoe3rd";
const invalid = "Jòhn꠵Çoe日本語3rd";

console.log(valid.match(alphanumeric));
console.log(invalid.match(alphanumeric));

\p{sc=Latn}\p{Script=Latin}的缩写。 \p{Nd}\p{Decimal_Number}的缩写,匹配十进制数。与\d的区别在于,\p{Nd}不仅匹配5,还匹配等可能更多的内容。

有关详细信息,请查看正则表达式Unicode文档,可用的\p选项链接在文档页面上。

请注意,u标志不受Internet Explorer支持


9

I would create a String prototype method:

String.prototype.isAlphaNumeric = function() {
  var regExp = /^[A-Za-z0-9]+$/;
  return (this.match(regExp));
};

然后,使用方式将是:
var TCode = document.getElementById('TCode').value;
return TCode.isAlphaNumeric()

8
可维护的 JavaScript:不要修改你不拥有的对象在编写 JavaScript 代码时,我们经常需要操作各种对象。然而,在处理来自其他地方的对象时,可能会因为意外的修改导致代码难以维护。为了保持代码的可维护性,建议避免修改你不拥有的对象。取而代之的是,应该使用这些对象提供的公共接口来实现所需的功能。如果必须修改其他人的对象,请确保你已经了解了该对象的完整结构,并进行了适当的测试和文档记录。 - SeinopSys
3
DJDavid98:我认为“不要修改你不拥有的对象”的规则在这里并不适用。Justin只是扩展了String的功能,而不是修改现有的功能。就C#世界而言,这将被视为扩展方法的完全有效使用。即使某一天浏览器制造商实现了“String.isAlphaNumeric(): boolean”,其签名和操作也不会实际改变,因此我无法看到在这个特定示例中有任何可维护性的减少。规则并不意味着没有例外。 - Risto Välimäki

8

在紧密的循环中,最好避免使用正则表达式并硬编码您的字符:

const CHARS = new Set("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
function isAlphanumeric(char) {
    return CHARS.has(char);
}

你能解释一下这个吗? - lazydeveloper
2
这段代码在循环中扫描整个字符串时是O(N^2)的,性能比最差的正则表达式解决方案还要糟糕(例如用户传入所有的'Z',indexOf()必须为每个字符扫描到末尾)。它不仅可能产生扫描整个0-Z字符串的开销(平均每次执行18个字符比较),而且每个源字符串字符还会有两个函数调用的开销 - 这是一个相当显著的常数时间值!该代码甚至可能会引入DoS漏洞,具体取决于它的使用位置。 - CubicleSoft
1
你是绝对正确的,CubicleSoft。我已经更新答案使用JS Set。 - Malganis
@CubicleSoft 我认为集合的复杂度通常是哈希映射的典型,根据我所读的资料,它的复杂度为O(1)。您知道任何证实此算法复杂度为O(N^2)的来源吗? - jakubiszon
@jakubiszon 答案已由发布者从原始答案进行了更新。请查看编辑记录。原始答案是在字符串上使用indexOf()函数。 - CubicleSoft
这个回答(现在已经被编辑过)在性能方面如何与Michael Martin-Smucker的回答相比? - OOPS Studio

8
这是一些注意事项:真正的字母数字字符串像 "0a0a0a0b0c0d",而不是像 "000000""qwertyuio"
我读到的所有答案,在两种情况下都返回了 true。这是不正确的。
如果我想检查我的字符串"00000"是否为字母数字,我的直觉无疑是错误的。为什么?很简单。我找不到任何字母字符。因此,它只是一个简单的数字字符串[0-9]
另一方面,如果我想检查我的字符串"abcdefg",我的直觉仍然是错误的。我看不到数字,所以它不是字母数字。只是字母[a-zA-Z]Michael Martin-Smucker's answer非常有启发性。
然而,他的目标是实现更好的性能而不是正则表达式。使用低级方式确实可以获得更好的性能。但结果是相同的。 字符串"0123456789"(仅数字),"qwertyuiop"(仅字母)和"0a1b2c3d4f4g"(字母数字混合)作为字母数字混合返回TRUE。与同样是/^[a-z0-9]+$/i的正则表达式相同。 正则表达式无法工作的原因很简单,也很明显。语法[]表示,而不是并且。 因此,如果它只是数字或者只是字母,正则表达式会返回true

但是,Michael Martin-Smucker的回答仍然很有启发性。对我来说。 它让我能够以“低级别”的方式思考,创建一个明确处理字母数字字符串的实际函数。我像使用PHP相关函数ctype_alnum一样调用它(编辑2020-02-18:但是,这检查OR而不是AND)。

以下是代码:


function ctype_alnum(str) {
  var code, i, len;
  var isNumeric = false, isAlpha = false; // I assume that it is all non-alphanumeric

  for (i = 0, len = str.length; i < len; i++) {
    code = str.charCodeAt(i);

    switch (true) {
      case code > 47 && code < 58: // check if 0-9
        isNumeric = true;
        break;

      case (code > 64 && code < 91) || (code > 96 && code < 123): // check if A-Z or a-z
        isAlpha = true;
        break;

      default:
        // not 0-9, not A-Z or a-z
        return false; // stop function with false result, no more checks
    }
  }

  return isNumeric && isAlpha; // return the loop results, if both are true, the string is certainly alphanumeric
}

And here is a demo:

function ctype_alnum(str) {
  var code, i, len;
    var isNumeric = false, isAlpha = false; //I assume that it is all non-alphanumeric

    
loop1:
  for (i = 0, len = str.length; i < len; i++) {
    code = str.charCodeAt(i);
        
        
        switch (true){
            case code > 47 && code < 58: // check if 0-9
                isNumeric = true;
                break;
            case (code > 64 && code < 91) || (code > 96 && code < 123): //check if A-Z or a-z
                isAlpha = true;
                break;
            default: // not 0-9, not A-Z or a-z
                return false; //stop function with false result, no more checks
                
        }

  }
    
  return isNumeric && isAlpha; //return the loop results, if both are true, the string is certainly alphanumeric
};

$("#input").on("keyup", function(){

if ($(this).val().length === 0) {$("#results").html(""); return false};
var isAlphaNumeric = ctype_alnum ($(this).val());
    $("#results").html(
        (isAlphaNumeric) ? 'Yes' : 'No'
        )
        
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input id="input">

<div> is Alphanumeric? 
<span id="results"></span>
</div>

这是Michael Martin-Smucker在JavaScript中的方法实现。

2
以上代码解决的是 alphaAndNumeric,不是 alphaNumeric。return isNumeric || isAlpha; 是 alphaNumeric。以上内容可能对某些人有所帮助。 - TamusJRoyce
1
@TamusJRoyce 当然可以。但是想象一下要检查一些VAT号码,有些情况下只是数字,而在其他情况下必须是字母和数字。顺便说一句,我现在才意识到我的失误,相对的PHP函数预见了OR而不是AND。这是一个问题,因为我不得不修改所有我的PHP应用程序代码,创建一个特定函数来提供AND。 - Oscar Zarrus
我认为一个真正的字母数字字符串应该是平衡的,其中50%的字符是字母,另外一半是数字。只有一个数字字符的"qw3rtyuio"很难被认为是纯数字的。 - AnnanFay
我觉得一个真正的字母数字字符串应该是平衡的,其中50%的字符是字母,另外一半是数字。只有一个数字字符的"qw3rtyuio"很难被认为是数字。 - undefined

7
    // On keypress event call the following method
    function AlphaNumCheck(e) {
        var charCode = (e.which) ? e.which : e.keyCode;
        if (charCode == 8) return true;

        var keynum;
        var keychar;
        var charcheck = /[a-zA-Z0-9]/;
        if (window.event) // IE
        {
            keynum = e.keyCode;
        }
        else {
            if (e.which) // Netscape/Firefox/Opera
            {
                keynum = e.which;
            }
            else return true;
        }

        keychar = String.fromCharCode(keynum);
        return charcheck.test(keychar);
    }

此外,这篇文章还有助于理解JavaScript字母数字验证。


4

要检查input_string是否为字母数字组合,只需使用以下代码:

input_string.match(/[^\w]|_/) == null

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