Code Golf: проверка адреса электронной почты без регулярных выражений
(Edit: What's Code Golf: Code Golf - это проблемы для решения конкретной проблемы с наименьшим количеством кода по количеству символов, которые вы предпочитаете. Подробнее здесь в Meta StackOverflow.)
Code Golfers, вот вызов строковых операций.
Проверка адресов электронной почты, но без регулярных выражений (или аналогичной библиотеки синтаксического анализа). Это не столько об адресах электронной почты, сколько о том, насколько короткими вы можете написать различные строковые операции и ограничения, приведенные ниже.
Правила следующие (да, я знаю, это не соответствует RFC, но это будут 5 правил для этой задачи):
-
Как минимум 1 символ из этой группы перед @:
A-Z, a-z, 0-9, . (period), _ (underscore)
-
@должно существовать ровно один раз
[email protected]
^
-
Период (.) должен существовать ровно через один раз после @
[email protected]
^
-
Не менее 1 только символ [A-Z, a-z] между @и следующим. (Период)
[email protected]
^
-
По крайней мере 2 только символы [A-Z, a-z] после финала. Период
[email protected]
^^
Пожалуйста, опубликуйте только метод/функцию, которая возьмет строку (предложенный адрес электронной почты), а затем вернет логический результат (true/false) в зависимости от того, какой адрес электронной почты действителен (true) или недействителен (false).
Samples:
[email protected] (valid/true) @w.org (invalid/false)
[email protected]@d.org (invalid/false) [email protected] (invalid/false)
[email protected]%.org (invalid/false) s%[email protected] (invalid/false)
[email protected] (invalid/false) [email protected] (valid/true)
[email protected] (valid/true) [email protected]%.com (invalid/false)
Удачи!
Ответы
Ответ 1
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("[email protected]"));
assert(e("[email protected]"));
assert(e("[email protected]"));
assert(!e("[email protected]@d.org"));
assert(!e("[email protected]%.org"));
assert(!e("[email protected]"));
assert(!e("@w.org"));
assert(!e("[email protected]"));
assert(!e("s%[email protected]"));
assert(!e("[email protected]%.com"));
puts("success!");
}
Ответ 2
:[[/%^(:[[+-/^,&i|:[$[' ']^j+0__:k<3:]]
Ответ 3
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()
, поэтому я чувствую, что этот ответ не такой "чистый", как строгарный ответ, который без каких-либо функций библиотеки. (Я также украл его идею объявить глобальную переменную без типа!)
Один из трюков заключается в том, что, положив .
и _
в начале строки A
, можно легко включить или исключить их в тесте strspn()
: когда вы хотите разрешить им, используйте strspn(something, A)
; Если вы этого не сделаете, используйте strspn(something, A+12)
. Другой предполагает, что sizeof (short) == 2 * sizeof (char)
и создание массива действительных символов 2 за раз из пары "семя" Aa
. Остальное просто искало способ заставить подвыражения выглядеть достаточно похожими, чтобы их можно было вытащить в макросы #define
d.
Чтобы сделать этот код более "портативным" (heh: -P), вы можете изменить код построения массива из
char A[66]="_.0123456789Aa";short*s=A+12;for(;++s<A+64;)*s=s[-1]+257;
к
char*A="_.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
за 5 дополнительных символов.
Ответ 4
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]
В основном просто машина состояния, использующая обнюхивающие короткие имена переменных.
Ответ 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;}
Требуется одна новая строка, и я подсчитал ее как один символ.
Ответ 6
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:
assert v("[email protected]")
assert v("[email protected]")
assert v("[email protected]")
assert not v("[email protected]@d.org")
assert not v("[email protected]%.org")
assert not v("[email protected]")
assert not v("@w.org")
assert not v("[email protected]")
assert not v("s%[email protected]")
assert not v("[email protected]%.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
: буква, число, символ подчеркивания, период, знак at (изменение состояния до 2
, если найдено "@
" )
- В состоянии
2
: письмо (изменить состояние на 3
)
- В состоянии
3
: буква, период (изменение состояния до 4, если найденный период)
- В состояниях
4
thru 6
: буква (состояние приращения при 4
или 5
)
Когда мы прошли весь путь через строку, мы возвращаем, будет ли t==6
(t>5
меньше char), а o
равно 1.
Ответ 7
Независимо от версии С++ MSVC2008.
Здесь мое скромное подчинение. Теперь я знаю, почему они сказали мне никогда не делать то, что я сделал здесь:
#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;
}
Ответ 8
Не самое большое решение, без сомнения, и довольно чертовски многословное, но оно действительно.
Исправлено (все тестовые примеры проходят сейчас)
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;
}
Ответ 9
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 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 = "[email protected]"; printf("%s ==> %d\n", t, v(t));
t = "[email protected]"; printf("%s ==> %d\n", t, v(t));
t = "[email protected]"; printf("%s ==> %d\n", t, v(t));
t = "[email protected]@d.org"; printf("%s ==> %d\n", t, v(t));
t = "[email protected]%.org"; printf("%s ==> %d\n", t, v(t));
t = "[email protected]"; printf("%s ==> %d\n", t, v(t));
t = "@w.org"; printf("%s ==> %d\n", t, v(t));
t = "[email protected]"; printf("%s ==> %d\n", t, v(t));
t = "s%[email protected]"; printf("%s ==> %d\n", t, v(t));
t = "[email protected]%.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 абсолютно отвратительно!
Проверьте мою первую (багги) версию.
Ответ 10
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;}
Проходит все тесты (моя старшая версия была неправильной).
Ответ 11
VBA/VB6 - 484 символа
Явное выключение
использование: VE ( "[email protected]" )
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
Ответ 12
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([[email protected]|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("[email protected]"),
false = e("[email protected]@d.org"),
false = e("[email protected]%.org"),
false = e("[email protected]"),
true = e("[email protected]"),
false = e("[email protected]"),
false = e("s%[email protected]"),
true = e("[email protected]"),
false = e("[email protected]%.com"),
ok.
Ответ 13
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
Ответ 14
'Без использования регулярного выражения:
PHP 47 Chars.
<?=filter_var($argv[1],FILTER_VALIDATE_EMAIL);
Ответ 15
Haskell (GHC 6.8.2), 165 161 144C Персонажи
Использование сопоставления с образцом, elem
, span
и all
:
a=['A'..'Z']++['a'..'z']
e=f.span(`elem`"._0123456789"++a)
f(_:_,'@':d)=g$span(`elem`a)d
f _=False
g(_:_,'.':[email protected](_:_:_))=all(`elem`a)t
g _=False
Выше было протестировано со следующим кодом:
main :: IO ()
main = print $ and [
e "[email protected]",
e "[email protected]",
e "[email protected]",
not $ e "[email protected]@d.org",
not $ e "[email protected]%.org",
not $ e "[email protected]",
not $ e "@w.org",
not $ e "[email protected]",
not $ e "s%[email protected]",
not $ e "[email protected]%.com"
]