2015-11-11 4 views
10

So habe ich eine Zeichenfolge, die ich durch Semikolon derE-Mail-Adresse Spaltung

E-Mail-Adresse teilen müssen: "[email protected];,.'o"@hotmail.com;"some;thing"@example.com

Sowohl der E-Mail-Adressen gültig sind

Deshalb möchte ich haben ein List<string> der folgenden Möglichkeiten:

Aber die Art, wie ich zur Zeit die Adressen am Aufspalten funktioniert nicht:

var addresses = emailAddressString.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries) 
       .Select(x => x.Trim()).ToList(); 

Wegen der mehrfachen ; Charaktere, die ich am Ende mit ungültige E-Mail-Adressen

Ich habe ein paar verschiedene Möglichkeiten ausprobiert, sogar hinunter arbeiten, wenn die Zeichenfolge Zitate enthält und dann den Index der ; Zeichen finden und es auf diese Weise funktioniert, aber es ist ein echter Schmerz.

Hat jemand bessere Vorschläge?

+1

würde Mein Vorschlag sicherstellen, dass Ihr Begrenzungszeichen nicht irgendwo anders nicht auftauchen als die Grenze zu markieren zwischen E-Mails, so sollten E-Mails mit ';' als Teil ihres Namens (zB "einige; [email protected]") nicht erlaubt sein. Andernfalls finde ein anderes Trennzeichen, wie eine Pipe '|'? – ray

+0

RegEx zur Rettung? Vielleicht können Sie anpassen: http://stackoverflow.com/questions/7430186/regex-split-string-with-on-a-delimetersemi-colon-except-those-that-appear-in – Corak

+1

Versuchen Sie Folgendes: '(^ |;) (. *?) @ ([\ d \ w] + [-] *) + \. \ w + ' – Camo

Antwort

4

Ich begann offensichtlich meine Anti-Regex-Methode etwa zur gleichen Zeit wie juharr (eine andere Antwort) zu schreiben. Ich dachte, da ich es schon geschrieben habe, würde ich es einreichen.

public static IEnumerable<string> SplitEmailsByDelimiter(string input, char delimiter) 
    { 
     var startIndex = 0; 
     var delimiterIndex = 0; 

     while (delimiterIndex >= 0) 
     { 
      delimiterIndex = input.IndexOf(';', startIndex); 
      string substring = input; 
      if (delimiterIndex > 0) 
      { 
       substring = input.Substring(0, delimiterIndex); 
      } 

      if (!substring.Contains("\"") || substring.IndexOf("\"") != substring.LastIndexOf("\"")) 
      { 
       yield return substring; 
       input = input.Substring(delimiterIndex + 1); 
       startIndex = 0; 
      } 
      else 
      { 
       startIndex = delimiterIndex + 1; 
      } 
     } 
    } 

Dann wurde die folgende

  var input = "[email protected];\"[email protected];,.'o\"@hotmail.com;\"some;thing\"@example.com;[email protected];[email protected];"; 
      foreach (var email in SplitEmailsByDelimiter(input, ';')) 
      { 
       Console.WriteLine(email); 
      } 

würde diese Ausgabe geben

[email protected] 
"[email protected];,.'o"@hotmail.com 
"some;thing"@example.com 
[email protected] 
[email protected] 
13

Unter der Annahme, dass doppelte Anführungszeichen sind nicht erlaubt, außer für das Öffnen und Schließen zitiert vor dem „auf“ Zeichen @, können Sie diesen regulären Ausdruck verwenden, um E-Mail-Adressen zu erfassen:

((?:[^@"]+|"[^"]*")@[^;]+)(?:;|$) 

Die Idee ist, entweder einen nicht notierten [^@"]+ oder einen "[^"]*" Teil vor @ zu erfassen und dann alles bis zum Semikolon ; oder dem Endanker $ zu erfassen.

Demo of the regex.

var input = "\"[email protected];,.'o\"@hotmail.com;\"some;thing\"@example.com;[email protected]"; 
var mm = Regex.Matches(input, "((?:[^@\"]+|\"[^\"]*\")@[^;]+)(?:;|$)"); 
foreach (Match m in mm) { 
    Console.WriteLine(m.Groups[1].Value); 
} 

Dieser Code druckt

"[email protected];,.'o"@hotmail.com 
"some;thing"@example.com 
[email protected] 

Demo 1.

Wenn Sie entkam doppelte Anführungszeichen in doppelte Anführungszeichen ermöglichen möchten, können Sie einen komplexeren Ausdruck verwenden:

((?:(?:[^@\"]|(?<=\\)\")+|\"([^\"]|(?<=\\)\")*\")@[^;]+)(?:;|$) 

Alles andere bleibt gleich.

Demo 2.

+0

Vielen Dank für Ihre Hilfe. Ich habe mir die Haare ausgezogen! –

+0

Was ist, wenn doppelte Anführungszeichen zulässig sind? –

+0

@JamieR Es hängt von den Regeln des Zulassens zusätzlicher Anführungszeichen ab. Wenn zusätzliche Anführungszeichen innerhalb von Strings in Anführungszeichen erlaubt sind, aber sie müssen maskiert sein, dann würde dieser Teil "[^"] * "'der Regex viel kniffliger werden, aber immer noch praktikabel. Es wären überall uneingeschränkte doppelte Anführungszeichen möglich mehrdeutig – dasblinkenlight

3

Sie können dies auch tun, ohne reguläre Ausdrücke zu verwenden. Mit der folgenden Erweiterungsmethode können Sie ein Trennzeichen und ein Zeichen zum Starten und Beenden von Escape-Sequenzen angeben. Beachten Sie, dass nicht überprüft wird, dass alle Escape-Sequenzen geschlossen sind.

public static IEnumerable<string> SpecialSplit(
    this string str, char delimiter, char beginEndEscape) 
{ 
    int beginIndex = 0; 
    int length = 0; 
    bool escaped = false; 
    foreach (char c in str) 
    { 
     if (c == beginEndEscape) 
     { 
      escaped = !escaped; 
     } 

     if (!escaped && c == delimiter) 
     { 
      yield return str.Substring(beginIndex, length); 
      beginIndex += length + 1; 
      length = 0; 
      continue; 
     } 

     length++; 
    } 

    yield return str.Substring(beginIndex, length); 
} 

Dann wurde die folgende

var input = "\"[email protected];,.'o\"@hotmail.com;\"some;thing\"@example.com;[email protected];\"D;[email protected];blah.com\""; 
foreach (var address in input.SpecialSplit(';', '"')) 
    Console.WriteLine(v); 

Während geben diesem Ausgang

"[email protected];,.'o"@hotmail.com

"etwas, das Ding" @ beispiel.com

hallo @ welt

"D; D @ blah; blah.com" ist

Hier ist die Version, die mit einem zusätzlichen Einzel Escape-Zeichen funktioniert. Es wird davon ausgegangen, dass zwei aufeinanderfolgende Escape-Zeichen zu einem einzigen Escape-Zeichen werden sollten und es sowohl der beginEndEscape Charta entgeht, so dass es den Anfang oder das Ende einer Escape-Sequenz nicht auslöst, und es auch die delimiter entkommt. Alles andere, was nach dem Escape-Zeichen folgt, wird beibehalten, wenn das Escape-Zeichen entfernt wird.

public static IEnumerable<string> SpecialSplit(
    this string str, char delimiter, char beginEndEscape, char singleEscape) 
{ 
    StringBuilder builder = new StringBuilder(); 
    bool escapedSequence = false; 
    bool previousEscapeChar = false; 
    foreach (char c in str) 
    { 
     if (c == singleEscape && !previousEscapeChar) 
     { 
      previousEscapeChar = true; 
      continue; 
     } 

     if (c == beginEndEscape && !previousEscapeChar) 
     { 
      escapedSequence = !escapedSequence; 
     } 

     if (!escapedSequence && !previousEscapeChar && c == delimiter) 
     { 
      yield return builder.ToString(); 
      builder.Clear(); 
      continue; 
     } 

     builder.Append(c); 
     previousEscapeChar = false; 
    } 

    yield return builder.ToString(); 
} 

Schließlich sollten Sie wahrscheinlich null für die Zeichenfolge Überprüfung hinzufügen, die in und beachten Sie übergeben wird, dass sowohl eine Sequenz mit einem leeren String zurück, wenn Sie in einem leeren String.

+0

Was ist, wenn innerhalb des '' 'ein anderes' '' zB '" sehr.(),:; <> [] \ ". VERY. \" very @ \\ "sehr \". ungewöhnlich "@ strange.example.com' –

+0

In diesem Fall müssen Sie ihm auch sagen, dass es ein Escape-Zeichen für das doppelte Anführungszeichen gibt. Sie müssen dann auch darüber nachdenken, was entkommt und was nicht "Angenommen" \\ "wird Ihnen einen einzelnen Backslash geben, aber was ist mit" \ t ". Möchten Sie einen Tab oder einfach so? single t? – juharr

+3

Auch würde ich wahrscheinlich mit "string.Substring" aufgeben und stattdessen einen 'StringBuilder' verwenden, um Zeichen hinzuzufügen, während ich die Daten durchlaufe. – juharr

Verwandte Themen