tags:

views:

133

answers:

4

Hi, i am trying to extract the username from this uri field in ANSI C code on linux using gcc

mail:[email protected]

so i need to strip the mail: and everything after the @. Are there any built in functions in C to extract substrings

+5  A: 
char *uri_field = "mail:[email protected]";

char username[64];

sscanf(uri_field, "mail:%63[^@]", username);

If you might have other "junk" at the beginning (not necessarily just mail:), you could do something like this instead:

sscanf(uri_field, "%*[^:]:%63[^@]", username);
Jerry Coffin
works very well,thanks
tech74
did not know you could do this with scanf, very nice :)
Matt Joiner
@Matt: it is pretty cool, isn't it? The single thing I miss the most when I use C++ iostreams is anything equivalent to scanf's `%[whatever]` and `%[^whatever]`.
Jerry Coffin
better is if( 1==sscanf(uri_field, "mail:%63[^@]", username) ), isnt it?
@gordongekko: yes, you usually want to check for errors (especially when you're dealing with user input), though unless that's the subject at hand, I usually leave (most) error checking out of answers like this for the sake of clarity.
Jerry Coffin
A: 
void getEmailName(const char *email, char **name /* out */) {
    if (!name) {
        return;
    }

    const char *emailName = strchr(email, ':');

    if (emailName) {
        ++emailName;
    } else {
        emailName = email;
    }

    char *emailNameCopy = strdup(emailName);

    if (!emailNameCopy) {
        *name = NULL;

        return;
    }

    char *atSign = strchr(emailNameCopy, '@');

    if (atSign) {
        *atSign = '\0'; // To remove the '@'
        // atSign[1] = '\0';  // To keep the '@'
    }

    if (*name) {
        strcpy(*name, emailNameCopy);
    } else {
        *name = emailNameCopy;
    }
}

This creates a pointer to the : character (colon) within the string. (It does not make a copy of the string.) If the : is found, point to the character after it. If the : doesn't exist, just use the beginning of the string (i.e. assume no mail: prefix).

Now we want to strip everything from the @ onward, so we make a copy of the string (emailNameCopy) and later cut off the @.

The code then creates a pointer to the @ character (atSign) within the string. If the @ character exists (i.e. strchr returns non-NULL), the character at the @ is set to zero, marking the end of the string. (A new copy isn't made.)

We then return the string, or copy it if a buffer was given.

strager
Note this is C99. I'm not sure if `strdup` is standard (I was always confused about that bit), but reading man should tell you what it does and it's easy to reproduce in a few lines of code.
strager
@strager: just FWIW, no `strdup` is not standard (though it is pretty common). Officially, the name is reserved so if you write one yourself, you get undefined behavior. Anybody who's really bothered by that can just use another name that doesn't start with `str`.
Jerry Coffin
+2  A: 

You could use also strtok. Look at this example

/* strtok example */
#include <stdio.h>
#include <string.h>

    int main ()
    {
      char str[] ="mail:[email protected]";
      char * pch;
      pch = strtok (str," :@");
      while (pch != NULL)
      {
        printf ("%s\n",pch);
        pch = strtok (NULL, " :@");
      }
      return 0;
    }

Hope it helps.

rlbisbe
A: 

Another solution, which does not rely in any special possibility, and is easily capable of detecting errors is the following one. Note that you'll have to free the string when the function extractUsername() succeeds.

Note that in C you just navigate in a sequence of chars, using pointer arithmetic. There are a few standard library functions, but they are much more simpler than anything able to extract information from the string.

There are still other issues for error detection, such as the presence of more than one '@', for example. But this should be enough as a starting point.

// Extract "mail:[email protected]"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

const char * MailPrefix = "mail:";
const char AtSign = '@';

char * extractUserName(const char * eMail)
{
    int length = strlen( eMail );
    char * posAtSign = strrchr( eMail, AtSign );
    int prefixLength = strlen( MailPrefix );

    char * toret = (char *) malloc( length + 1 );
    if ( toret != NULL
      && posAtSign != NULL
      && strncmp( eMail, MailPrefix, prefixLength ) == 0 )
    {
        memset( toret, 0, length  +1 );
        strncpy( toret, eMail + prefixLength, posAtSign - prefixLength - eMail );
    }
    else {
        free( toret );
        toret = NULL;
    }

    return toret;
}

int main()
{
    const char * test = "mail:[email protected]";

    char * userName = extractUserName( test );

    if ( userName != NULL ) {
        printf( "User name: '%s'\n", userName );
        free( userName );
    } else {
        fprintf( stderr, "Error: invalid e.mail address\n" );
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}
Baltasarq