J'essaie d'extraire le nom d'utilisateur de ce champ URI dans le code ANSI C sous Linux à l'aide de GCC
mail:username@example.com
4 Réponses :
sscanf(uri_field, "%*[^:]:%63[^@]", username);
Je ne savais pas que tu pouvais le faire avec Scanf, très gentil :)
@Matt: C'est assez cool, n'est-ce pas? La seule chose qui me manque le maximum lorsque j'utilise C ++ iostreams est tout ce qui équivaut à l'équivalent au % de Scanf [quoi que ce soit] code> et % [^ autre] code>.
Mieux vaut si (1 == SSCANF (URI_Field, "Mail:% 63 [^ @]", nom d'utilisateur)), n'est-ce pas?
@gordongekkkko: Oui, vous souhaitez généralement vérifier les erreurs (surtout lorsque vous avez affaire à une entrée utilisateur), cependant à moins que ce soit le sujet à portée de main, je quitte généralement (la plupart) erreur de vérification des réponses comme celle-ci pour la clarté .
@Jerrycoffin: Je rencontre des problèmes pour obtenir le serveur de sapins dans /etc/resolv.conf en utilisant un seul FSCANF. J'ai essayé FSCANF (FP, "% * noms de noms:% 20 [^ \ n]", adresse); code> quel retour 0 (aucun résultat n'a été trouvé); Et adresse code> est vide. (Oui, le fichier a été ouvert avec succès avant avec fopen).
@ user2284570: Votre chaîne de format n'a pas de sens. Compte tenu du format normal d'un fichier /etc/resolv.conf, vous voulez quelque chose du genre: FSCANF (FP, "noms de noms% 20 [^ \ n]", adresse); code>
@Jerrycoffin: Cela ne fonctionne que dans un cas rare (c'est la première chose que j'ai essayée) car resolv.conf ne commence souvent pas par noms de noms code> au début du fichier. La plupart du temps, le fichier commence par les commentaires («# généré par NetworkManager») ou d'autres paramètres tels que domaines code> ou Rechercher code>.
@ user2284570: Oui - Pour une telle situation, vous avez généralement besoin / que vous souhaitez lire une ligne, tenter de le numériser comme type de ligne que vous vous souciez, vérifiez le retour de SSCANF pour voir si cela réussissait et ignorez simplement le ligne et passer à la suivante si elle n'a pas réussi.
@Jerrycoffin. Je ne veux pas copier le fichier dans un tampon (c'est pourquoi je souhaite utiliser un seul FSCANF pour obtenir le résultat directement, et non SRTOK). J'ai juste besoin d'un seul serveur de noms. J'ai besoin de la "regex" exacte (je sais que ce n'est pas vraiment regex) qui signifierait tout avec une longueur de contenus Unkknow Contourne jusqu'à ce que "nomerver". Parce que % * code> ne semble pas être la bonne solution, ni une erreur dans mon expression.
@ user2284570: Je ne pense pas que cela puisse être fait avec une seule chaîne de format FSCANF. Le problème est que (par exemple) une ligne commençant par # code> doit être ignorée complètement - il pourrait contenir un serveur de noms non valide code>. Commentaires axés sur la ligne donnés, vous avez à peu près besoin de lire une ligne, puis de l'ignorer si c'est un commentaire.
@JerryCoffin: Dans mon cas, le resolv.conf est toujours généré par une application tierce partie. Donc, je sais qu'une ligne ne sera jamais commentée. (Mon application fonctionnera localement et ne sera pas publique). Alors avez-vous des idées pour la "regex"? s'il te plaît...
@ user2284570: si vous avez (par exemple) 3 lignes de commentaire suivies d'une ligne de noms code> code>, vous pouvez utiliser quelque chose comme: FSCANF (dans, "% * [^ \ n]% * [ ^ \ n]% * [^ \ n] noms de noms% 20 [^ \ n] ", adresse); code>
@Jerrycoffin: laissez-nous Continuer cette discussion en chat
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.
Notez que c'est C99. Je ne suis pas sûr si STRUP code> est standard (j'ai toujours été confondu à propos de ce bit), mais l'homme de lecture devrait vous dire ce qu'il fait et il est facile de reproduire dans quelques lignes de code.
Juste Fwiw, aucun STRUP code> n'est pas standard (bien qu'il soit assez courant). Officiellement, le nom est réservé, donc si vous vous écrivez un vous-même, vous obtenez un comportement indéfini. Toute personne qui est vraiment dérangée par cela peut simplement utiliser un autre nom qui ne commence pas par str code>.
Vous pouvez également utiliser espère que cela aide. P> p> strtok code>. Regardez cet exemple
Une autre solution, qui ne repose pas dans une possibilité particulière et est facilement capable de détecter des erreurs est la suivante. Notez que vous devrez libérer la chaîne lorsque la fonction EXTRASSERName () réussite.
Notez que dans C, vous ne naviguez que dans une séquence de caractères, à l'aide de pointeur arithmétique. Il existe quelques fonctions de bibliothèque standard, mais elles sont beaucoup plus simples que tout ce qui est capable d'extraire des informations de la chaîne. P>
Il existe toujours d'autres problèmes de détection d'erreur, tels que la présence de plus d'un '@ ', par example. Mais cela devrait être suffisant comme point de départ. P>
// Extract "mail:username@example.com"
#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:baltasarq@gmail.com";
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;
}