LIANXU.me

I create software and I design.

Web应用中一种用户友好Email验证模式

每过一段时间,我的网站和论坛就会出现注册邮件错误问题。而且往往是缺少某个字符这样的错误。例如:hotmail.com写成了hotmai.com 对于这种意图明确但又不容易发现的错误,普通邮件格式验证函数是无法处理的。因为这种拼写错误依然属于合法邮件地址。但是一个友好的Web页面应该给与用户适当的提示。这里我提出一个容易想到的简单方法处理这个问题。

我们计算用户输入的邮件域和一些常见邮件域的 Levenshtein Distance,也称作字符串编辑距离,是指从一个字符串转换到另一个字符串最小的编辑操作次数。对于LD足够小但又不为0的情况,给于用户提示。

下面给出Levenshtein Distance的js实现代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
function levenshtein(a, b) {
    var i;
    var j;
    var cost;
    var d = new Array();

    if (a.length == 0) {
        return b.length;
    }

    if (b.length == 0) {
        return a.length;
    }

    for (i = 0; i <= a.length; i++) {
        d[i] = new Array();
        d[i][0] = i;
    }

    for (j = 0; j <= b.length; j++) {
        d[0][j] = j;
    }

    for (i = 1; i <= a.length; i++) {
        for (j = 1; j <= b.length; j++) {

          cost = (a.charAt(i - 1) == b.charAt(j - 1)) ? 0 : 1;
          
            d[i][j] = Math.min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + cost);

            if (i > 1 && j > 1 &&
              a.charAt(i - 1) == b.charAt(j - 2) &&
              a.charAt(i - 2) == b.charAt(j - 1)) {
                d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + cost)
            }
        }
    }
    return d[a.length][b.length];
}

接下来我们要准备一些常用的邮件域信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
function checkCommonMail(id,errorid) {
    var email = document.getElementById(id).value;
    var useremailDomain=email.substring(email.indexOf("@")+1).toLowerCase();
      var error=document.getElementById(errorid);
      
      var commonDomain = [
          "hotmail.com",
          "gmail.com",
          ["yahoo.cn","yahoo.hk","yahoo.com.cn","yahoo.com.hk","yahoo.com"],
          "163.com",
          "sina.com",
          "live.com",
          "qq.com",
          "vip.qq.com"];

  for(var i=0;i<commonDomain.length;i++){
      if (commonDomain[i] instanceof Array) {
          var pardomain=commonDomain[i];
          var dis=new Array();
          for(var j=0;j<pardomain.length;j++){
              dis[j]=levenshtein(useremailDomain,pardomain[j]);
          }
          var mindis=100000,minj=0;
          for(var j=0;j<dis.length;j++){
              if(dis[j]==0) return;
              if(dis[j]<mindis) {
                  mindis=dis[j];
                  minj=j;
              }
          }
          if(mindis==0) return;
          if(mindis<3){
              error.innerHTML = '您的邮件地址很像'+pardomain[minj]+'?';
          }
          delete dis;
          return;
      }else{
          var dis=levenshtein(useremailDomain,commonDomain[i]);
          if(dis==0) return;
          if(dis<2){
              error.innerHTML = '您的邮件地址很像'+commonDomain[i]+'?';
              return;
          }
          delete dis;
      }
  }
}

上面的函数中yahoo域为并列结算,这样计算更符合用户的意图。

该方式适用处理用户无意间输入的错误。当然你可以同时配合邮箱格式验证函数,来过滤掉一些完全错误的邮箱输入:

1
2
3
4
5
6
7
8
9
function checkMail(id) {
  var email = document.getElementById(id).value;
    var pattern = /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/;
    if (pattern.test(email)) {
        return true;
    } else {
        return false;
    }
}

最后加一句题外话。作为一个普通的程序员,应该能够合理的应用上述功能函数。但是作为一个优秀的程序员,应该能理解上述函数算法。通过阅读上面levenshtein函数,优秀的程序员应该立即识别出这是一个典型的动态规划算法,哪里是动态转移方程,时间复杂度大概是什么等等。

Javascript, UX, Web Development

« 世界第一个红唇Emoji域名 Cocoa中NSString到NSDate的处理 »

Comments