Email validation in C++
Asked Answered
B

11

6

Okay so I'm trying to make a program which allows user to input their email. Their email will be considered valid if two stipulations are met: A. there must be an "@" sign somewhere in there and B. there must be a period after the "@". I got the code down for the most part, but I am having some difficulty when it comes to validating emails that have a period before the "@" sign. If they have the period before the "@" sign they are considered valid, but they shouldn't be. For example, entering text.example@randomcom is considered valid.

Can anyone help me figure out what I did wrong? Thank you in advance!

#include <iostream>
#include <cctype>
#include <cstring>
using namespace std;

int main()
{
    int x = 25; //random size enough to hold contents of array plus one for               null terminator
    char input[x]; //array to hold input
    int sizeOf; //holds length of input array
    char* ptr = nullptr; //pointer
    char* ptr2 = nullptr; //pointer

    cout << "Enter your email address\n";
    cin.getline(input,x);
    sizeOf = strlen(input);

    for(int i = 0; i < sizeOf; i++)
    {
        ptr= strstr(input, "@"); //searches input array for "@" string
        if(ptr != nullptr) 
        {
            break;
        }
    }

    for(int i = 0; i < sizeOf; i++)
    {
        ptr2 = strstr(input, "."); //searches input array for "." string
        if(ptr2 != nullptr && &ptr2 > &ptr)
        {
            break;
        }
    }

    if(ptr != nullptr) //validates input of "@" sign
    {
        if(ptr2 != 0 && &ptr2 < &ptr) 
            {
                cout << "Email accepted.\n";
            }

        else
            {
                cout << "Missing . symbol after @\n";
            }
    }

    else
    {
        cout << "Missing @ symbol\n";
    }



return 0;
}
Bolinger answered 28/4, 2016 at 2:2 Comment(4)
A 25 character buffer for an email address? I'm not sure if I should cry because that's ridiculously short. Your program will take the express train to undefined behaviour as soon as someone has the audacity to type in an address longer than that. [email protected] is a modest length address that is too long by 4 characters for your code. This is why fixed-length C style buffers are really bad news.Academe
The title might be misleading as this is more "validation of a subset of emails", email validation is surprisingly complex.Arda
Some email addresses might not contain a dot in the domain. See RFC2822 for details. Email address validation is a tar-baby.Isreal
Are you restricted to using <cstring> ? Or can you use <algorithm> and <regex>?Tricksy
R
16

Why not use regex?

#include <iostream>
#include <string>
#include <regex>

bool is_email_valid(const std::string& email)
{
   // define a regular expression
   const std::regex pattern
      ("(\\w+)(\\.|_)?(\\w*)@(\\w+)(\\.(\\w+))+");

   // try to match the string with the regular expression
   return std::regex_match(email, pattern);
}

int main()
{
    std::string email1 = "text.example@randomcom";

    std::cout << email1 << " : " << (is_email_valid(email1) ?
      "valid" : "invalid") << std::endl;
}

http://en.cppreference.com/w/cpp/regex

Roquelaure answered 28/4, 2016 at 2:15 Comment(4)
"Now you have two problems," courtesy of the very man who created Stack Overflow! blog.codinghorror.com/…Comma
You're checking for a . or _ before the @? That's not in the requirements, but the rest looks good.Midyear
(\\w+) <- I understood but why (\\.) working perfectly, I meant only one \ should be there, right?Cascabel
No hyphens allowed?Menstruation
C
4
static bool IsEmailAddress(const std::string& str)
{
    // Locate '@'
    auto at = std::find(str.begin(), str.end(), '@');
    // Locate '.' after '@'
    auto dot = std::find(at, str.end(), '.');
    // make sure both characters are present
    return (at != str.end()) && (dot != str.end());
}
Chatty answered 5/4, 2018 at 0:31 Comment(2)
1. Try to locate '@' character. <br/> 2. Try to locate '.' character after '@' character. <br/> 3. If both 1 and 2 are satisfied, the input string is a valid email. <br/>Chatty
The explanation should be in the answer.Meritorious
G
3

The main problem here is that this is supposed to be a C++ program, but, instead, it became a C program. strstr() and strlen() are C library functions.

In modern C++ we use std::string, iterators, and algorithms, which make the whole task much shorter, and easier to grok. And there's no need to worry about buffer overflows, either:

#include <string>
#include <algorithm>

// Your main() declaration here, etc...

std::string input;

std::cout << "Enter your email address" << std::endl;
std::getline(std::cin, input);

auto b=input.begin(), e=input.end();

if (  (b=std::find(b, e, '@')) != e &&
      std::find(b, e, '.') != e )
{
    std::cout << "Email accepted" << std::endl;
}
else
{
    std::cout << "Email rejected" << std::endl;
}

Now, isn't that shorter, and easier to parse?

Garica answered 28/4, 2016 at 2:9 Comment(6)
That if condition is beyond the reach of many mere mortals. I had to read it a few times to make sure it was correct. Not easy to understand.Comma
My mind works in mysterious ways. I find it easier to wrap my brain around iterators, than keep track of index-based solutions that use find().Garica
The problem is not the use of iterators--iterators are fine. The problem is the double-condition in the if where the first condition modifies the arguments of the second. Plus the bonus of comparing the result of an assignment with a third value (but hey, at least you added the appropriate parens to make it less impenetrable).Comma
I highly appreciate the help but I have to agree with John, this code is a little too over my head to fully grasp. Alas, I'm barely in Introduction to CS.Bolinger
Same point about unchecked use of getline that I made under John's answer applies here....Midyear
Using strstr() and strlen() doesn't make it a C program.Tricksy
C
1

Use std::string, not that nasty fixed-size C string stuff.

int main()
{
    string input;
    cout << "Enter your email address\n";
    getline(cin, input);

    size_t at = input.find('@');
    if (at == string::npos)
    {
        cout << "Missing @ symbol\n";
        return 1;
    }

    size_t dot = input.find('.', at + 1);
    if (dot == string::npos)
    {
        cout << "Missing . symbol after @\n";
        return 2;
    }

    cout << "Email accepted.\n";
    return 0;
}
Comma answered 28/4, 2016 at 2:11 Comment(2)
I'd suggest - if (cin >> input) { ... } else { ...err... } - avoids issues with leading/trailing/embedded whitespace (assuming post-whitespace content will be validated somehow afterwards) and lines that don't contain any non-whitespace, or - if you want to make sure it's the very next line of input that contains the email, keep using getline but check it succeeds and trim whitespace / check for empty input afterwards.Midyear
But this doesn't tests for if email contains multiple '@' symbol. Only one '@' should be separating the address from domain name. All other '@' should be inside double quotes.Lobectomy
P
1

I have improved dshvets1 code for checking locat part and domain length:

bool IsEmailAddress(const std::string& str)
{
        if (str.size() > 150)
            return false;

        const auto at = std::find(str.cbegin(), str.cend(), '@');
        const auto dot = std::find(at, str.cend(), '.');

        if((at == str.cend()) || (dot == str.cend()))
            return false;

        if (std::distance(str.cbegin(), at) < 1) //~@ - is minimal local part
            return false;

        if(std::distance(at, str.cend()) < 5 )  //@i.ua - is minimal domain
            return false;

        return true;
}
Pamphleteer answered 11/2, 2021 at 14:23 Comment(0)
T
0

You have very restricted and specific rules about valid email addresses that are not reflective of real email addresses. Assuming that's intentional, the main problem I see is you are writing loops when you do not need to. The library function strstr() does the looping for you. You just pass it the string and it will loop through it looking for the char.

So, letting the function do the finding for you, you can divide and conquer the problem like this:

bool is_valid(char const* email)
{
    auto at_pos = std::strchr(email, '@');

    if(at_pos == nullptr)
        return false; // did not find an '@' (rule A violation)

    auto dot_pos = std::strchr(email, '.');

    if(dot_pos == nullptr)
        return false; // did not find an '.' (rule B violation)

    if(dot_pos < at_pos)
        return false; // '.' found before '@' (rule B violation)

    return true; // all rules followed!
}
Tricksy answered 17/2, 2019 at 19:31 Comment(0)
R
0

Try using the below method.

bool ValidateEmail(string email)
{
    if (regex_match(email, regex("([a-z]+)([_.a-z0-9]*)([a-z0-9]+)(@)([a-z]+)([.a-z]+)([a-z]+)"))) 
        return true;

    return false;
}
Radioactivity answered 2/9, 2019 at 20:25 Comment(0)
N
0

Peace of Cake Regex is here for Unreal Engine C++

bool IsValidEmailAddressFormat(const FString& String)
{
    const FRegexPattern Pattern(TEXT("^([a-z0-9]+)((\\.|-|_)([a-z0-9])+)*@([a-z0-9]+)(\\.([a-z0-9]{2,8}+))+$"));
    FRegexMatcher Matcher(Pattern, String);

    return Matcher.FindNext();
}
Ninepins answered 26/7, 2023 at 6:29 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Hua
G
-2

when you search the @ character, then after that instead of searching '.' from beginning of the string, you can start from the previous value of i variable.

Note:- I did not think much on this and all other cases.

Goldeneye answered 24/6, 2018 at 7:20 Comment(0)
C
-2

It should be:

if(ptr2 != 0 && &ptr2 >&ptr)

instead of:

if(ptr2 != 0 && &ptr2 < &ptr)
Cherimoya answered 16/10, 2018 at 14:47 Comment(1)
No, both are wrong. First, comparing pointers to different variables with > is not well-defined. Second, it has no benefit at all in this program. (The & was probably not desired)Meritorious
L
-2
//Program to validate email

#include<iostream>                 //header files
#include<string>

using namespace std;

int strLength(char str[]);

int email_check(char str[])
{                                               //function to check the conditions for email
int size,pos=0,pos1=0,c=0;
size=strLength(str);
if((str[0]>='a'&& str[0]<='z')||(str[0]>='A'&& str[0]<='Z'))  //first char should be an alphabet
{
for(int i=0;i<size;i++)
{
if((str[i]>='a'&& str[i]<='z')||(str[i]>='0' && str[i]<='9') || str[i]=='.'||str[i]=='_'||str[i]=='-'||str[i]=='#'||str[i]=='@')                                         //combination of characters allowed
{
if(str[i]=='.'||str[i]=='_'||str[i]=='-'||str[i]=='#'||str[i]=='@')    // symbol encountered 
{
if((str[i+1]>='a'&&str[i+1]<='z')||(str[i+1]>='0' &&str[i+1]<='9')) //no 2 repeated symbols
{
if(str[i]=='@')                       //@ encountered, so domain part begins
pos=i;                                  //pos is the position where domain begins
}
else
return 0;
}
}
else
return 0;
}
}
else
return 0;
if(pos==0)
return 0;
else
{
for(int j=pos+1;j<size;j++)
{
if(str[pos+1]>='a'&&str[pos+1]<='z')
{
if(str[j]=='.') 
pos1=j;
}
else
return 0;
}
}
if(pos1==0)
return 0;
else
{
for(int k=pos1+1;k<size;k++)
{
if(str[k]>='a'&&str[k]<='z')
c++;
else
return 0;
}
if(c>=2)
return 1;
else
return 0;
}                                           
}                                           //end of function

int main()
{
int c;
char email[100],ch;
do
{
cout<<"\nEnter email: ";
cin.get(email , 100)    ;                                 //accepting email from user
c=email_check(email);
if(c==1)                     //if all criteria matched
{
cout<<"\nemail accepted...\n";

cout<<"\nYour email address is: ";
puts(email);
break;
}
else                               //criteria not matched
{
cout<<"\nInvalid email";
cout<<"\n\nWant to re-enter email(y/n): ";
cin>>ch;
}
}while(ch=='y'||ch=='Y');   //user is asked to enter again until the choice is yes
return 1;
}


int strLength(char str[]) {

    int k = 0;
    for(k = 0 ; ;k++){
        if(str[k] == '\0')
            break;
    }
    return k;
}
Lickspittle answered 17/2, 2019 at 17:1 Comment(1)
I hardly know where to begin.Meritorious

© 2022 - 2024 — McMap. All rights reserved.