8

Trying to create a regex pattern for email address check. That will allow a dot (.) but not if there are more than one next to each other.

Should match: test.test@test.com

Should not match: test..test@test.com

Now I know there are thousands of examples on internet for e-mail matching, so please don't post me links with complete solutions, I'm trying to learn here.

Actually the part that interests me the most is just the local part: test.test that should match and test..test that should not match. Thanks for helping out.

Martin Schröder
  • 4,176
  • 7
  • 47
  • 81
Carbon6
  • 113
  • 1
  • 1
  • 7
  • The spec defines how you should match it http://tools.ietf.org/html/rfc2822#page-17 . It will be much easier to built robust regex that way than use the ad hoc solutions here that only look at the problem of 2 dots – Esailija May 20 '12 at 14:00
  • Actually I was going through that specifications... And came to my first obstacle trying to learn regex matching a dot but not two or more next to each other. – Carbon6 May 20 '12 at 14:38
  • 1
    Well it says local part is either dot-atom or quoted string, then you look up what dot-atom is which is 1 atomtext followed by optionally a dot and another atom text. Which is automatically a regex that disqualifies strings starting with dot, ending with dot, or having two or more successive dots in the middle. For simplicity, assume atomtext is just characters a-z. Then local part that allows only dot atoms is: `/^([a-z](?:\.[a-z])*)+$/` – Esailija May 20 '12 at 15:08

5 Answers5

6

You may allow any number of [^\.] (any character except a dot) and [^\.])\.[^\.] (a dot enclosed by two non-dots) by using a disjunction (the pipe symbol |) between them and putting the whole thing with * (any number of those) between ^ and $ so that the entire string consists of those. Here's the code:

$s1 = "test.test@test.com";
$s2 = "test..test@test.com";
$pattern = '/^([^\.]|([^\.])\.[^\.])*$/';
echo "$s1: ", preg_match($pattern, $s1),"<p>","$s2: ", preg_match($pattern, $s2);

Yields:

test.test@test.com: 1
test..test@test.com: 0
YakovL
  • 7,557
  • 12
  • 62
  • 102
Junuxx
  • 14,011
  • 5
  • 41
  • 71
  • second part might be `\.{1}` – challet Sep 21 '17 at 13:02
  • it should be noted that this doesn't allow dots in the end and in the beginning of the string – YakovL Feb 26 '18 at 15:53
  • and shouldn't it actually be `'/^([^\.]|([^\.]\.[^\.]))*$/'` instead of `'/^([^\.]|([^\.])\.[^\.])*$/'`? (parentheses around the `[^\.]\.[^\.])`, not just `[^\.]`) – YakovL Feb 26 '18 at 16:53
  • @YakovL: It doesn't matter, in fact the inner parentheses could just be left out. Parentheses have lower precedence than the disjunction, so it is still parsed correctly. – Junuxx Feb 26 '18 at 20:57
5

This seams more logical to me:

/[^.]([\.])[^.]/

And it's simple. The look-ahead & look-behinds are indeed useful because they don't capture values. But in this case the capture group is only around the middle dot.

Mihai Stancu
  • 15,848
  • 2
  • 33
  • 51
  • This is true if there is a single dot anywhere in the string, it would match both examples. – Junuxx May 20 '12 at 13:58
1
strpos($input,'..') === false

strpos function is more simple, if `$input' has not '..' your test is success.

MajidTaheri
  • 3,813
  • 6
  • 28
  • 46
0
^([^.]+\.?)+@$

That should do for the what comes before the @, I'll leave the rest for you. Note that you should optimise it more to avoid other strange character setups, but this seems sufficient in answering what interests you

Don't forget the ^ and $ like I first did :(

Also forgot to slash the . - silly me

YakovL
  • 7,557
  • 12
  • 62
  • 102
Bilal Akil
  • 4,716
  • 5
  • 32
  • 52
  • That was fast! And basicaly answered my question. Thanks. But, is there a way to form a pattern without positive match. This will return true on test..test@ because it will match last part text@ – Carbon6 May 20 '12 at 14:29
  • Yep sorry about that, forgot the ^ and $, should now return true for test.test@ and false for test..test@ – Bilal Akil May 20 '12 at 22:42
0

To answer the question in the title, I'd update the RegExp by Junuxx and allow dots in the beginning and end of the string:

'/^\.?([^\.]|([^\.]\.))*$/'

which is optional . in the beginning followed by any number of non-. or [non-. followed by .].

YakovL
  • 7,557
  • 12
  • 62
  • 102