所以我有一个字符串,我需要用分号
分割电子邮件地址:"one@tw;,.'o"@hotmail.com;"some;thing"@example.com
这两个电子邮件地址均有效
所以我希望得到以下List<string>
:
但我目前分割地址的方式不起作用:
var addresses = emailAddressString.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries)
.Select(x => x.Trim()).ToList();
由于多个;
个字符,我最终会收到无效的电子邮件地址。
我尝试过几种不同的方法,如果字符串包含引号,然后找到;
字符的索引并按照这种方式进行处理,那么就会解决问题,但这真的很痛苦。
有没有人有更好的建议?
答案 0 :(得分:13)
假设不允许使用双引号,除了&#34; at&#34;之前的开头报价和收盘价。签署@
,您可以使用此正则表达式来捕获电子邮件地址:
((?:[^@"]+|"[^"]*")@[^;]+)(?:;|$)
我们的想法是在[^@"]+
之前捕获不带引号的"[^"]*"
或引用的@
部分,然后将所有内容捕获到分号;
或结束锚{ {1}}。
$
此代码打印
var input = "\"one@tw;,.'o\"@hotmail.com;\"some;thing\"@example.com;hello@world";
var mm = Regex.Matches(input, "((?:[^@\"]+|\"[^\"]*\")@[^;]+)(?:;|$)");
foreach (Match m in mm) {
Console.WriteLine(m.Groups[1].Value);
}
如果您希望在双引号内允许转义双引号,则可以使用更复杂的表达式:
"one@tw;,.'o"@hotmail.com
"some;thing"@example.com
hello@world
其他一切都保持不变。
答案 1 :(得分: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 = "blah@blah.com;\"one@tw;,.'o\"@hotmail.com;\"some;thing\"@example.com;hello@world;asdasd@asd.co.uk;";
foreach (var email in SplitEmailsByDelimiter(input, ';'))
{
Console.WriteLine(email);
}
会提供此输出
blah@blah.com
"one@tw;,.'o"@hotmail.com
"some;thing"@example.com
hello@world
asdasd@asd.co.uk
答案 2 :(得分: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 = "\"one@tw;,.'o\"@hotmail.com;\"some;thing\"@example.com;hello@world;\"D;D@blah;blah.com\"";
foreach (var address in input.SpecialSplit(';', '"'))
Console.WriteLine(v);
虽然给出了这个输出
&#34;一个@ TW;,&#39; O&#34; @ hotmail.com
&#34;一些;东西&#34; @ example.com
您好@世界
&#34; d; d @等等; blah.com&#34;
这是使用附加单个转义字符的版本。它假定两个连续的转义字符应该成为一个转义字符,并且它会转义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
检查传入的字符串,并注意如果传入一个空字符串,两者都将返回一个带有一个空字符串的序列。