2015-11-11 60 views
10

所以,我有我需要用分号的电子邮件地址拆分

电子邮件地址来分割字符串:"[email protected];,.'o"@hotmail.com;"some;thing"@example.com

两个电子邮件地址是有效的

所以我想有a List<string>以下:

但我目前分裂地址的方式是行不通的:

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

由于多个;字符我最终的无效的电邮地址。

我试过几种不同的方法,即使下去工作,如果字符串包含引号,然后找到;字符的索引,并以这种方式工作,但这是一个真正的痛苦。

有没有人有更好的建议?

+1

我的建议是,以确保您的分隔符不显示任何其他地方以外,以纪念边界在电子邮件之间,所以不应该允许带'''的电子邮件作为他们名字的一部分(例如“some; [email protected]”)。否则,找到一个不同的分隔符,如管道'|'? – ray

+0

正规救援?也许你可以适应:http://stackoverflow.com/questions/7430186/regex-split-string-with-on-a-delimetersemi-colon-except-those-that-appear-in – Corak

+1

尝试以下方法:'(^ |;)(。*?)@([\ d \ w] + [ - ] *)+ \。\ w +' – Camo

回答

4

我明显开始写作我的反正则表达式方法大约与juharr同时(另一个答案)。我认为,既然我已经写好了,我会提交它。

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; 
      } 
     } 
    } 

那么下面

  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); 
      } 

愿意给这个输出

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

假定双引号是不允许的,除了开启和关闭的“at”符号@行情的未来,你可以使用这个正则表达式捕捉到的电子邮件地址:

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

的的想法是在@之前捕获未加引号的[^@"]+或引用的"[^"]*"部分,然后捕获所有内容,直到分号为;或结束锚点$

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); 
} 

此代码打印

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

Demo 1.

如果你想允许双引号内的转义双引号,你可以使用一个更复杂的表达式:

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

其他一切保持不变。

Demo 2.

+0

谢谢你的帮助。一直把我的头发拉出来! –

+0

如果允许双引号会怎么样? –

+0

@JamieR这取决于允许额外的双引号的规则。如果在引用的字符串中允许使用额外的双引号,但是它们必须被转义,那么正则表达式的这部分''[^“] *”'会变得更加棘手,但仍然可行。允许任何地方不受限制的双引号暧昧 – dasblinkenlight

3

你也可以做到这一点,而无需使用正则表达式。下面的扩展方法将允许你指定一个分隔字符和一个字符来开始和结束转义序列。请注意,它不验证所有转义序列都已关闭。

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); 
} 

那么下面

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); 

虽然给这个输出

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

“一些;事” @ example.com

hello @ world

“d; d @等等; blah.com”

下面是一个额外的单转义字符工作的版本。它假设两个连续的转义字符应该成为一个单一的转义字符,并且它同时逃脱了两个beginEndEscape章程,所以它不会触发转义序列的开始或结束,它也会转义delimiter。转义字符后面的任何其他内容都将与转义字符一起被删除。

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(); 
} 

最后你应该添加null检查传递进来,请注意,这两个将返回一个序列与一个空字符串,如果你在一个空字符串传递字符串。

+0

如果在'''里面有另一个''''例如''very。(),:; <> [] \“。 \“非常\”非常“@ strange.example.com” –

+0

在这种情况下,您还需要告诉它双引号有一个转义字符,并且您还必须考虑可以和不能转义的内容。Presumeable“\\”会给你一个单一的反斜杠,但是“\ t”怎么办?你想要一个标签还是只是单身? – juharr

+3

另外我可能会放弃使用'string.Substring',而是使用'StringBuilder'来添加字符,因为我循环访问数据。 – juharr

相关问题