Code Golf:没有正则表达式的电子邮件地址验证

时间:2009-09-07 17:25:29

标签: code-golf rosetta-stone

(编辑:什么是Code Golf: Code Golf是解决特定问题的挑战,使用您喜欢的任何语言中的字符数最少的代码。 More info here在Meta StackOverflow上。)

Code Golfers,这是对字符串操作的挑战。

电子邮件地址验证,但没有正则表达式(或类似的解析库)当然。它不是关于电子邮件地址,而是你可以写下下面给出的不同字符串操作和约束的时间。

规则如下(是的,我知道,这不符合RFC,但这些将成为此挑战的5条规则):

  • 在@:

    之前,该组中至少有一个字符
    A-Z, a-z, 0-9, . (period), _ (underscore)
    
  • @必须存在,恰好一次

    john@smith.com
        ^
    
  • 句号(。)必须在@

    后恰好存在一次
    john@smith.com
              ^
    
  • @和以下之间至少有1个 [A-Z,a-z] 字符。 (周期)

    john@s.com
         ^
    
  • 决赛后至少2个 [A-Z,a-z] 个字符。期

    john@smith.ab
               ^^
    

请仅发布方法/函数,这将采用字符串(建议的电子邮件地址),然后返回布尔结果(true / false),具体取决于有效的电子邮件地址(true)或无效(false)

Samples:
b@w.org    (valid/true)          @w.org     (invalid/false)    
b@c@d.org  (invalid/false)       test@org   (invalid/false)    
test@%.org (invalid/false)       s%p@m.org  (invalid/false)    
j_r@x.c.il (invalid/false)       j_r@x.mil  (valid/true)
r..t@x.tw  (valid/true)          foo@a%.com (invalid/false)
祝你好运!

15 个答案:

答案 0 :(得分:20)

C89(166个字符)

#define B(c)isalnum(c)|c==46|c==95
#define C(x)if(!v|*i++-x)return!1;
#define D(x)for(v=0;x(*i);++i)++v;
v;e(char*i){D(B)C(64)D(isalpha)C(46)D(isalpha)return!*i&v>1;}

不可重入,但可以多次运行。试验台:

#include<stdio.h>
#include<assert.h>
main(){
    assert(e("b@w.org"));
    assert(e("r..t@x.tw"));
    assert(e("j_r@x.mil"));
    assert(!e("b@c@d.org"));
    assert(!e("test@%.org"));
    assert(!e("j_r@x.c.il"));
    assert(!e("@w.org"));
    assert(!e("test@org"));
    assert(!e("s%p@m.org"));
    assert(!e("foo@a%.com"));
    puts("success!");
}

答案 1 :(得分:12)

J

:[[/%^(:[[+-/^,&i|:[$[' ']^j+0__:k<3:]]

答案 2 :(得分:6)

C89,175个字符。

#define G &&*((a+=t+1)-1)==
#define H (t=strspn(a,A
t;e(char*a){char A[66]="_.0123456789Aa";short*s=A+12;for(;++s<A+64;)*s=s[-1]+257;return H))G 64&&H+12))G 46&&H+12))>1 G 0;}

我正在使用标准库函数strspn(),因此我觉得这个答案不像strager的答案那样“干净”,没有任何库函数。 (我也偷了他一个没有类型声明全局变量的想法!)

这里的一个技巧是,将._放在字符串A的开头,可以在strspn()中轻松地包含或排除它们测试:当你想允许它们时,使用strspn(something, A);如果不这样做,请使用strspn(something, A+12)。另一个是假设sizeof (short) == 2 * sizeof (char),并且一次从“种子”对Aa构建有效字符数组2。其余的只是寻找一种方法来强制子表达式看起来足够相似,以便可以将它们拉出#define d宏。

要使此代码更“可移植”(呵呵:-P),您可以从

更改数组构建代码
char A[66]="_.0123456789Aa";short*s=A+12;for(;++s<A+64;)*s=s[-1]+257;

char*A="_.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

需要额外支付5个字符。

答案 3 :(得分:5)

Python(181个字符,包括换行符)

def v(E):
 import string as t;a=t.ascii_letters;e=a+"1234567890_.";t=e,e,"@",e,".",a,a,a,a,a,"",a
 for c in E:
  if c in t[0]:t=t[2:]
  elif not c in t[1]:return 0>1
 return""==t[0]

基本上只是一个使用混淆的短变量名的状态机。

答案 4 :(得分:5)

C(166个字符)

#define F(t,u)for(r=s;t=(*s-64?*s-46?isalpha(*s)?3:isdigit(*s)|*s==95?4:0:2:1);++s);if(s-r-1 u)return 0;
V(char*s){char*r;F(2<,<0)F(1=)F(3=,<0)F(2=)F(3=,<1)return 1;}

需要单个换行符,我将其计为一个字符。

答案 5 :(得分:4)

Python,149个字符(将整个for循环放入一个以分号分隔的行之后,我为了“可读性”目的而没有在这里做过)​​:

def v(s,t=0,o=1):
 for c in s:
   k=c=="@"
   p=c=="."
   A=c.isalnum()|p|(c=="_")
   L=c.isalpha()
   o&=[A,k|A,L,L|p,L,L,L][t]
   t+=[1,k,1,p,1,1,0][t]
 return(t>5)&o

测试用例,借鉴strager's answer

assert v("b@w.org")
assert v("r..t@x.tw")
assert v("j_r@x.mil")
assert not v("b@c@d.org")
assert not v("test@%.org")
assert not v("j_r@x.c.il")
assert not v("@w.org")
assert not v("test@org")
assert not v("s%p@m.org")
assert not v("foo@a%.com")
print "Yeah!"

解释:迭代字符串时,两个变量不断更新。

t保持当前状态:

  • t = 0:我们刚开始。
  • t = 1:我们从一开始就找到了至少一个合法字符(字母,数字,下划线,句号)
  • t = 2:我们找到了“@
  • t = 3:我们至少在“@”之后找到了合法字符(即字母)
  • t = 4:我们在域名中找到了句号
  • t = 5:我们在这段时间后找到了一个合法字符(字母)
  • t = 6:我们在这段时间后找到了至少两个合法字符

o在“okay”中以1开头,即为true,并且一旦发现在当前状态下非法的字符,则设置为0。 法律人物是:

  • 状态0:字母,数字,下划线,句号(在任何情况下将状态更改为1
  • 状态1:字母,数字,下划线,句号,符号(如果找到“2”,则将状态更改为@
  • 状态2:字母(将状态更改为3
  • 状态3:字母,句点(如果找到句点,则将状态更改为4)
  • 状态46:字母(45时的增量状态)

当我们一直走过字符串时,我们会返回t==6t>5是否少一个字符)且o是否为1。

答案 6 :(得分:2)

无论MSVC2008支持哪种版本的C ++。

这是我的谦逊提交。现在我知道为什么他们告诉我永远不要做我在这里做的事情:

#define N return 0
#define I(x) &&*x!='.'&&*x!='_'
bool p(char*a) {
 if(!isalnum(a[0])I(a))N;
 char*p=a,*b=0,*c=0;
 for(int d=0,e=0;*p;p++){
  if(*p=='@'){d++;b=p;}
  else if(*p=='.'){if(d){e++;c=p;}}
  else if(!isalnum(*p)I(p))N;
  if (d>1||e>1)N;
 }
 if(b>c||b+1>=c||c+2>=p)N;
 return 1;
}

答案 7 :(得分:2)

毫无疑问,这不是最好的解决方案,而且相当冗长,但它是有效的。

已修复(所有测试用例现已通过)

    static bool ValidateEmail(string email)
{
    var numbers = "1234567890";
    var uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    var lowercase = uppercase.ToLower();
    var arUppercase = uppercase.ToCharArray();
    var arLowercase = lowercase.ToCharArray();
    var arNumbers = numbers.ToCharArray();
    var atPieces = email.Split(new string[] { "@"}, StringSplitOptions.RemoveEmptyEntries);
    if (atPieces.Length != 2)
        return false;
    foreach (var c in atPieces[0])
    {
        if (!(arNumbers.Contains(c) || arLowercase.Contains(c) || arUppercase.Contains(c) || c == '.' || c == '_'))
            return false;
    }
    if(!atPieces[1].Contains("."))
        return false;
    var dotPieces = atPieces[1].Split('.');
    if (dotPieces.Length != 2)
        return false;
    foreach (var c in dotPieces[0])
    {
        if (!(arLowercase.Contains(c) || arUppercase.Contains(c)))
            return false;
    }
    var found = 0;
    foreach (var c in dotPieces[1])
    {
        if ((arLowercase.Contains(c) || arUppercase.Contains(c)))
            found++;
        else
            return false;
    }
    return found >= 2;
}

答案 8 :(得分:2)

C89字符集不可知(262个字符)

#include <stdio.h>

/* the 'const ' qualifiers should be removed when */
/* counting characters: I don't like warnings :) */
/* also the 'int ' should not be counted. */

/* it needs only 2 spaces (after the returns), should be only 2 lines */
/* that's a total of 262 characters (1 newline, 2 spaces) */

/* code golf starts here */

#include<string.h>
int v(const char*e){
const char*s="0123456789._abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
if(e=strpbrk(e,s))
  if(e=strchr(e+1,'@'))
    if(!strchr(e+1,'@'))
      if(e=strpbrk(e+1,s+12))
        if(e=strchr(e+1,'.'))
          if(!strchr(e+1,'.'))
            if(strlen(e+1)>1)
              return 1;
return 0;
}

/* code golf ends here */

int main(void) {
  const char *t;
  t = "b@w.org"; printf("%s ==> %d\n", t, v(t));
  t = "r..t@x.tw"; printf("%s ==> %d\n", t, v(t));
  t = "j_r@x.mil"; printf("%s ==> %d\n", t, v(t));
  t = "b@c@d.org"; printf("%s ==> %d\n", t, v(t));
  t = "test@%.org"; printf("%s ==> %d\n", t, v(t));
  t = "j_r@x.c.il"; printf("%s ==> %d\n", t, v(t));
  t = "@w.org"; printf("%s ==> %d\n", t, v(t));
  t = "test@org"; printf("%s ==> %d\n", t, v(t));
  t = "s%p@m.org"; printf("%s ==> %d\n", t, v(t));
  t = "foo@a%.com"; printf("%s ==> %d\n", t, v(t));

  return 0;
}

第2版

仍然是C89字符集不可知,错误有希望得到纠正(303个字符; 284个没有#include)

#include<string.h>
#define Y strchr
#define X{while(Y
v(char*e){char*s="0123456789_.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
if(*e!='@')X(s,*e))e++;if(*e++=='@'&&!Y(e,'@')&&Y(e+1,'.'))X(s+12,*e))e++;if(*e++=='.'
&&!Y(e,'.')&&strlen(e)>1){while(*e&&Y(s+12,*e++));if(!*e)return 1;}}}return 0;}

#define X绝对令人作呕!

测试我的第一个(错误)版本。

答案 9 :(得分:1)

Java 257 字符(不包括3行的可读性;-))。

boolean q(char[]s){int a=0,b=0,c=0,d=0,e=0,f=0,g,y=-99;for(int i:s)
d=(g="@._0123456789QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm".indexOf(i))<0?
y:g<1&&++e>0&(b<1|++a>1)?y:g==1&e>0&(c<1||f++>0)?y:++b>0&g>12?f>0?d+1:f<1&e>0&&++c>0?
d:d:d;return d>1;}

通过所有测试(我的旧版本不正确)。

答案 10 :(得分:1)

VBA / VB6 - 484个字符

明确关闭
 用法:VE(“b@w.org”)

Function V(S, C)
V = True
For I = 1 To Len(S)
 If InStr(C, Mid(S, I, 1)) = 0 Then
  V = False: Exit For
 End If
Next
End Function

Function VE(E)
VE = False
C1 = "abcdefghijklmnopqrstuvwxyzABCDEFGHILKLMNOPQRSTUVWXYZ"
C2 = "0123456789._"
P = Split(E, "@")
If UBound(P) <> 1 Then GoTo X
If Len(P(0)) < 1 Or Not V(P(0), C1 & C2) Then GoTo X
E = P(1): P = Split(E, ".")
If UBound(P) <> 1 Then GoTo X
If Len(P(0)) < 1 Or Not V(P(0), C1) Or Len(P(1)) < 2 Or Not V(P(1), C1) Then GoTo X
VE = True
X:
End Function

答案 11 :(得分:1)

Erlang 266个字符:

-module(cg_email).

-export([test/0]).

%%% golf code begin %%%
-define(E,when X>=$a,X=<$z;X>=$A,X=<$Z).
-define(I(Y,Z),Y([X|L])?E->Z(L);Y(_)->false).
-define(L(Y,Z),Y([X|L])?E;X>=$0,X=<$9;X=:=$.;X=:=$_->Z(L);Y(_)->false).
?L(e,m).
m([$@|L])->a(L);?L(m,m).
?I(a,i).
i([$.|L])->l(L);?I(i,i).
?I(l,c).
?I(c,g).
g([])->true;?I(g,g).
%%% golf code end %%%

test() ->
  true  = e("b@w.org"),
  false = e("b@c@d.org"),
  false = e("test@%.org"),
  false = e("j_r@x.c.il"),
  true  = e("r..t@x.tw"),
  false = e("test@org"),
  false = e("s%p@m.org"),
  true  = e("j_r@x.mil"),
  false = e("foo@a%.com"),
  ok.

答案 12 :(得分:1)

Ruby 225个字符。 这是我的第一个Ruby程序,所以它可能不像Ruby那样: - )

def v z;r=!a=b=c=d=e=f=0;z.chars{|x|case x when'@';r||=b<1||!e;e=!1 when'.'
e ?b+=1:(a+=1;f=e);r||=a>1||(c<1&&!e)when'0'..'9';b+=1;r|=!e when'A'..'Z','a'..'z'
e ?b+=1:f ?c+=1:d+=1;else r=1 if x!='_'||!e|!b+=1;end};!r&&d>1 end

答案 13 :(得分:1)

'不使用正则表达式': PHP 47 Chars。

<?=filter_var($argv[1],FILTER_VALIDATE_EMAIL);

答案 14 :(得分:1)

Haskell(GHC 6.8.2), 165 161 144C字符


使用模式匹配,elemspanall

a=['A'..'Z']++['a'..'z']
e=f.span(`elem`"._0123456789"++a)
f(_:_,'@':d)=g$span(`elem`a)d
f _=False
g(_:_,'.':t@(_:_:_))=all(`elem`a)t
g _=False

使用以下代码测试上述内容:

main :: IO ()
main = print $ and [
  e "b@w.org",
  e "r..t@x.tw",
  e "j_r@x.mil",
  not $ e "b@c@d.org",
  not $ e "test@%.org",
  not $ e "j_r@x.c.il",
  not $ e "@w.org",
  not $ e "test@org",
  not $ e "s%p@m.org",
  not $ e "foo@a%.com"
  ]