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;
}
ETERNAL OBLIVION
  • 71
  • 2
  • 2
  • 6
  • 1
    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. `oblivion@eternaloblivion.com` 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. – tadman Apr 28 '16 at 02:11
  • 5
    The title might be misleading as this is more "validation of a subset of emails", email validation is [surprisingly complex](http://www.ex-parrot.com/~pdw/Mail-RFC822-Address.html). – user657267 Apr 28 '16 at 02:13
  • 3
    Some email addresses might not contain a dot in the domain. See RFC2822 for details. Email address validation is a tar-baby. – jbruni Apr 28 '16 at 02:40
  • Are you restricted to using `` ? Or can you use `` and ``? – Galik Feb 17 '19 at 19:04

11 Answers11

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

gonjay
  • 727
  • 2
  • 7
  • 13
  • 4
    "Now you have two problems," courtesy of the very man who created Stack Overflow! http://blog.codinghorror.com/regular-expressions-now-you-have-two-problems/ – John Zwinck Apr 28 '16 at 02:16
  • You're checking for a `.` or `_` before the `@`? That's not in the requirements, but the rest looks good. – Tony Delroy Apr 28 '16 at 02:27
  • (\\w+) <- I understood but why (\\.) working perfectly, I meant only one \ should be there, right? – Deep Shah Sep 28 '21 at 09:16
5
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());
}
dshvets1
  • 119
  • 1
  • 3
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?

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
  • 1
    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. – John Zwinck Apr 28 '16 at 02:13
  • 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(). – Sam Varshavchik Apr 28 '16 at 02:16
  • 1
    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). – John Zwinck Apr 28 '16 at 02:18
  • 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. – ETERNAL OBLIVION Apr 28 '16 at 02:20
  • 1
    Same point about unchecked use of `getline` that I made under John's answer applies here.... – Tony Delroy Apr 28 '16 at 02:31
  • Using `strstr()` and `strlen()` doesn't make it a `C` program. – Galik Feb 17 '19 at 19:06
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;
}
John Zwinck
  • 239,568
  • 38
  • 324
  • 436
  • 1
    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. – Tony Delroy Apr 28 '16 at 02:28
  • 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. – Himanshu Mittal Feb 05 '20 at 20:26
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;
}
Dmitry
  • 906
  • 1
  • 13
  • 32
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!
}
Galik
  • 47,303
  • 4
  • 80
  • 117
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;
}
Riddell
  • 1,429
  • 11
  • 22
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();
}
  • 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](/help/how-to-answer). – Community Jul 28 '23 at 20:54
-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.

-2

It should be:

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

instead of:

if(ptr2 != 0 && &ptr2 < &ptr)
Tomasz
  • 4,847
  • 2
  • 32
  • 41
  • 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) – Lightness Races in Orbit Feb 17 '19 at 17:08
-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;
}
Siddy Hacks
  • 1,846
  • 14
  • 15