2010-07-05 20 views
4

La classe MailAddress ne permet pas d'analyser une chaîne avec plusieurs e-mails. Le MailAddressCollection classe does, mais il accepte uniquement CSV et ne permet pas de virgules à l'intérieur des guillemets. Je suis à la recherche d'un processeur de texte pour créer une collection de courriels à partir de l'entrée de l'utilisateur sans ces restrictions.Extraction (multiple) des e-mails d'un texte saisi par l'utilisateur dans le format MailAddress (.NET)

Le processeur doit prendre des valeurs par des virgules ou séparés points-virgules dans ces formats:

"First Middle Last" <[email protected]> 
First Middle Last <[email protected]> 
[email protected] 
"Last, First" <[email protected]> 

Répondre

1

Après avoir demandé une related question, je pris conscience d'une meilleure méthode:

/// <summary> 
/// Extracts email addresses in the following formats: 
/// "Tom W. Smith" &lt;[email protected]&gt; 
/// "Smith, Tom" &lt;[email protected]&gt; 
/// Tom W. Smith &lt;[email protected]&gt; 
/// [email protected] 
/// Multiple emails can be separated by a comma or semicolon. 
/// Watch out for <see cref="FormatException"/>s when enumerating. 
/// </summary> 
/// <param name="value">Collection of emails in the accepted formats.</param> 
/// <returns> 
/// A collection of <see cref="System.Net.Mail.MailAddress"/>es. 
/// </returns> 
/// <exception cref="ArgumentException">Thrown if the value is null, empty, or just whitespace.</exception> 
public static IEnumerable<MailAddress> ExtractEmailAddresses(this string value) 
{ 
    if (string.IsNullOrWhiteSpace(value)) throw new ArgumentException("The arg cannot be null, empty, or just whitespace.", "value"); 

    // Remove commas inside of quotes 
    value = value.Replace(';', ','); 
    var emails = value.SplitWhilePreservingQuotedValues(','); 
    var mailAddresses = emails.Select(email => new MailAddress(email)); 
    return mailAddresses; 
} 

/// <summary> 
/// Splits the string while preserving quoted values (i.e. instances of the delimiter character inside of quotes will not be split apart). 
/// Trims leading and trailing whitespace from the individual string values. 
/// Does not include empty values. 
/// </summary> 
/// <param name="value">The string to be split.</param> 
/// <param name="delimiter">The delimiter to use to split the string, e.g. ',' for CSV.</param> 
/// <returns>A collection of individual strings parsed from the original value.</returns> 
public static IEnumerable<string> SplitWhilePreservingQuotedValues(this string value, char delimiter) 
{ 
    Regex csvPreservingQuotedStrings = new Regex(string.Format("(\"[^\"]*\"|[^{0}])+", delimiter)); 
    var values = 
     csvPreservingQuotedStrings.Matches(value) 
     .Cast<Match>() 
     .Select(m => m.Value.Trim()) 
     .Where(v => !string.IsNullOrWhiteSpace(v)); 
    return values; 
} 

Cette méthode passe les tests suivants:

[TestMethod] 
public void ExtractEmails_SingleEmail_Matches() 
{ 
    string value = "[email protected]"; 
    var expected = new List<MailAddress> 
     { 
      new MailAddress("[email protected]"), 
     }; 

    var actual = value.ExtractEmailAddresses(); 

    CollectionAssert.AreEqual(expected, actual.ToList()); 
} 

[TestMethod()] 
public void ExtractEmails_JustEmailCSV_Matches() 
{ 
    string value = "[email protected]; [email protected]"; 
    var expected = new List<MailAddress> 
     { 
      new MailAddress("[email protected]"), 
      new MailAddress("[email protected]"), 
     }; 

    var actual = value.ExtractEmailAddresses(); 

    CollectionAssert.AreEqual(expected, actual.ToList()); 
} 

[TestMethod] 
public void ExtractEmails_MultipleWordNameThenEmailSemicolonSV_Matches() 
{ 
    string value = "a a a <[email protected]>; a a a <[email protected]>"; 
    var expected = new List<MailAddress> 
     { 
      new MailAddress("a a a <[email protected]>"), 
      new MailAddress("a a a <[email protected]>"), 
     }; 

    var actual = value.ExtractEmailAddresses(); 

    CollectionAssert.AreEqual(expected, actual.ToList()); 
} 

[TestMethod] 
public void ExtractEmails_JustEmailsSemicolonSV_Matches() 
{ 
    string value = "[email protected]; [email protected]"; 
    var expected = new List<MailAddress> 
     { 
      new MailAddress("[email protected]"), 
      new MailAddress("[email protected]"), 
     }; 

    var actual = value.ExtractEmailAddresses(); 

    CollectionAssert.AreEqual(expected, actual.ToList()); 
} 

[TestMethod] 
public void ExtractEmails_NameInQuotesWithCommaThenEmailsCSV_Matches() 
{ 
    string value = "\"a, a\" <[email protected]>; \"a, a\" <[email protected]>"; 
    var expected = new List<MailAddress> 
     { 
      new MailAddress("\"a, a\" <[email protected]>"), 
      new MailAddress("\"a, a\" <[email protected]>"), 
     }; 

    var actual = value.ExtractEmailAddresses(); 

    CollectionAssert.AreEqual(expected, actual.ToList()); 
} 

[TestMethod] 
[ExpectedException(typeof(ArgumentException))] 
public void ExtractEmails_EmptyString_Throws() 
{ 
    string value = string.Empty; 

    var actual = value.ExtractEmailAddresses(); 
} 

[TestMethod] 
[ExpectedException(typeof(FormatException))] 
public void ExtractEmails_NonEmailValue_ThrowsOnEnumeration() 
{ 
    string value = "a"; 

    var actual = value.ExtractEmailAddresses(); 

    actual.ToList(); 
} 
+1

Même si, comme naasking dit, le MailAddressCollection ne supporte effectivement des virgules dans les chaînes entre guillemets, si elle renvoie une exception au format ne permet pas d'identifier exactement où l'erreur dans la chaîne est. Donc, cette réponse est bonne pour cette raison aussi: en séparant d'abord les emails, vous arrivez à identifier où le problème est susceptible de se produire, car il s'agit d'exceptions levées sur des constructeurs MailAddress individuels. – Gavin

1

La bibliothèque open source DotNetOpenMail (ancienne) a une classe EmailAddress qui peut analyser presque toutes les formes juridiques des adresses e-mail et un EmailAddressCollection. Vous pourriez commencer là.

0

En fait, MailAddressCollection pris en charge par des adresses séparées par des virgules, même avec les virgules à l'intérieur des citations. Le real problem I recently discovered, est que la liste CSV doit déjà être encodée dans le jeu de caractères ASCII, à savoir. Codé en Q ou en B pour les adresses Unicode.

Il n'y a aucune fonction dans les bibliothèques de classes de base pour effectuer ce codage, bien que je fournisse le codage B dans Sasa. J'ai également ajouté une fonction d'analyse de courrier électronique qui répond à la question dans ce fil de discussion.

2

La routine MailAddressCollection.Add() prend en charge une liste d'adresses délimitée par des virgules.

Dim mc As New Net.Mail.MailAddressCollection() 
mc.Add("Bob <[email protected]>, [email protected], ""John Doe"" <[email protected]>") 
For Each m As Net.Mail.MailAddress In mc 
    Debug.Print("{0} ({1})", m.DisplayName, m.Address) 
Next 

Sortie:

Bob ([email protected]) 
([email protected]) 
John Doe ([email protected]) 
+0

Vous manquez le point. Il ne supporte pas une virgule à l'intérieur des guillemets - '' Doe, John "' - il traite cela comme une virgule séparant les entrées plutôt que comme une partie d'une seule entrée. – Pat