Распределение адресов электронной почты
Итак, у меня есть строка, которую мне нужно разделить на точку с запятой
Адрес электронной почты: "[email protected];,.'o"@hotmail.com;"some;thing"@example.com
Оба адреса электронной почты действительны
Итак, я хочу иметь List<string>
из следующего:
- "один @ТВт;" о." @Hotmail.com
- "некоторые, вещь" @example.com
Но способ, которым я сейчас разбиваю адреса, не работает:
var addresses = emailAddressString.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries)
.Select(x => x.Trim()).ToList();
Из-за нескольких символов ;
у меня заканчиваются неверные адреса электронной почты.
Я пробовал несколько разных способов, даже если сработал, если строка содержит кавычки, а затем найдет индекс символов ;
и будет работать так, но это настоящая боль.
Есть ли у кого-нибудь лучшие предложения?
Ответы
Ответ 1
Я начал писать метод anti regex примерно в то же время, что и 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]
Ответ 2
Предполагая, что двойные кавычки не разрешены, кроме кавычек открытия и закрытия перед знаком "at" @
, вы можете использовать это регулярное выражение для захвата адресов электронной почты:
((?:[^@"]+|"[^"]*")@[^;]+)(?:;|$)
Идея состоит в том, чтобы зафиксировать либо некотируемую [^@"]+
, либо цитированную часть "[^"]*"
до @
, а затем захватить все до точки с запятой ;
или конечную привязку $
.
Демонстрация регулярного выражения.
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]
Демо 1.
Если вы хотите разрешить скрытые двойные кавычки внутри двойных кавычек, вы можете использовать более сложное выражение:
((?:(?:[^@\"]|(?<=\\)\")+|\"([^\"]|(?<=\\)\")*\")@[^;]+)(?:;|$)
Все остальное остается прежним.
Демо 2.
Ответ 3
Вы также можете сделать это, не используя регулярные выражения. Следующий метод расширения позволит вам указать символ разделителя и символ, чтобы начинать и заканчивать escape-последовательности. Обратите внимание, что он не подтверждает, что все escape-последовательности закрыты.
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);
Пока давайте этот выход
"один @ТВт;., 'О" @hotmail.com
"некоторые, вещь" @example.com
привет @мир
"D; D @л, blah.com"
Здесь версия, которая работает с дополнительным одиночным escape-символом. Он предполагает, что два последовательных escape-символа должны стать одним единственным escape-символом, и он ускользает от устава beginEndEscape
, чтобы он не запускал начало или конец escape-последовательности, а также избегал delimiter
. Все остальное, что появляется после escape-символа, будет оставлено так же, как и с удаленным символом.
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
проверку строки, которая передается, и обратите внимание, что оба возвращают последовательность с одной пустой строкой, если вы передадите пустую строку.