C# 电子邮件地址拆分

C# 电子邮件地址拆分,c#,C#,所以我有一个字符串,我需要用分号分开 电子邮件地址:“one@tw;,.“o”@hotmail.com;“some;thing”@example.com 两个电子邮件地址都有效 因此,我想列出以下内容的列表: "one@tw;,.'o“@hotmail.com “some;thing”@example.com 但我目前拆分地址的方式不起作用: var addresses = emailAddressString.Split(new[] { ';' }, StringSplitOptions.

所以我有一个字符串,我需要用分号分开

电子邮件地址:
“one@tw;,.“o”@hotmail.com;“some;thing”@example.com

两个电子邮件地址都有效

因此,我想列出以下内容的
列表

  • "one@tw;,.'o“@hotmail.com
  • “some;thing”@example.com
但我目前拆分地址的方式不起作用:

var addresses = emailAddressString.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries)
                .Select(x => x.Trim()).ToList();
因为有多个
字符以无效的电子邮件地址结尾

我已经尝试了几种不同的方法,甚至可以计算字符串是否包含引号,然后找到
的索引字符,并以这种方式工作,但这是一个真正的痛苦


有人有更好的建议吗?

假设不允许使用双引号,除了“at”符号前面的开始引号和结束引号之外。
@
,您可以使用此正则表达式捕获电子邮件地址:

((?:[^@"]+|"[^"]*")@[^;]+)(?:;|$)
其思想是在
@
之前捕获一个未被引用的
[^@”+
或一个被引用的
“[^”]*”
部分,然后捕获分号以内的所有内容
或端锚点
$

此代码打印

"one@tw;,.'o"@hotmail.com
"some;thing"@example.com
hello@world

如果希望在双引号内允许转义双引号,可以使用更复杂的表达式:

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

((?:(?:[^@\”]|)(?您也可以在不使用正则表达式的情况下执行此操作。以下扩展方法将允许您指定分隔符字符以及用于开始和结束转义序列的字符。请注意,它不会验证是否所有转义序列都已关闭

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);
}
同时给出这个输出

blah@blah.com
"one@tw;,.'o"@hotmail.com
"some;thing"@example.com
hello@world
asdasd@asd.co.uk
"one@tw;,.'o“@hotmail.com

“some;thing”@example.com

hello@world

“D;D@blah;blah.com“

这是一个使用附加单个转义字符的版本。它假设两个连续的转义字符应该成为一个转义字符,并且它转义了
beginEndEscape
章程,因此它不会触发转义序列的开始或结束,也转义了
分隔符转义字符后面的任何其他内容都将保留原样,并删除转义字符

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();
}
公共静态IEnumerable SpecialSplit(
此字符串为str、char分隔符、char beginedescape、char singleEscape)
{
StringBuilder=新的StringBuilder();
bool-escapedSequence=false;
bool-previousEscapeChar=false;
foreach(str中的字符c)
{
if(c==singleEscape&!previousEscapeChar)
{
previousEscapeChar=真;
继续;
}
if(c==begindescape&!previousEscapeChar)
{
escapedSequence=!escapedSequence;
}
if(!escapedSequence&&!previousEscapeChar&&c==分隔符)
{
收益率返回生成器.ToString();
builder.Clear();
继续;
}
附加(c);
previousEscapeChar=假;
}
收益率返回生成器.ToString();
}

最后,您可能应该添加
null
检查传入的字符串,并注意,如果传入空字符串,两者都将返回一个包含一个空字符串的序列。

很明显,我开始编写反正则表达式方法的时间与juharr差不多(另一个答案)1.我想既然我已经写好了,我就把它交上去

    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;
            }
        }
    }
将给出此输出

blah@blah.com
"one@tw;,.'o"@hotmail.com
"some;thing"@example.com
hello@world
asdasd@asd.co.uk

我的建议是确保您的分隔符不会出现在除标记电子邮件之间的边界之外的任何其他地方,因此将
作为其名称的一部分的电子邮件(例如,“some;thing@example.com")不应被允许。否则,请查找其他分隔符,如管道
?请尝试以下操作:
(^|)(.*)@([\d\w]+[-]*)+\不幸的是,我需要使用一个
字符,它在电子邮件中是有效的address@ray业务要求。@juharr:我同意,但通常不在电子邮件上下文中(例如csv文件)。这至少是我第一次在电子邮件地址设置中看到这种混乱,特别是因为我认为遵循有关电子邮件地址格式的“正常”做法非常简单。例如,一些电子邮件客户端(例如Outlook)在添加收件人时,请使用
来分隔地址,这样我可能无法向这样的“有效”收件人发送电子邮件“地址,如果它们出现了。谢谢你的帮助。我一直在为这件事发牢骚!如果允许双引号怎么办?@JamieR这取决于允许额外双引号的规则。如果允许在带引号的字符串中使用额外的双引号,但必须对其进行转义,则此部分
”[^]*"
的正则表达式将变得更加棘手,但仍然是可行的。允许不受限制的双引号无处不在将是不明确的。@JamieR是一个允许在引号字符串内部或外部转义引号的表达式。请注意,您需要在代码中取消这些引号的转义,因为它们会原封不动地传输到输出中。如果在表达式内部转义引号呢
还有另一个
例如
“very.,:;[]\.”very.“very.\\\\\\”very\.”非同寻常的“@strange.example.com
在这种情况下,你还需要告诉它双引号有一个转义字符。然后你还必须考虑什么可以转义,什么不能转义。可假定的“\\”将给您一个反斜杠,但“\t”如何。您想要一个制表符还是一个t?另外,我可能会放弃使用
string.Substring
,而是使用
StringBuilder
在循环数据时添加字符。
            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