Парсинг строки электронной почты


Моя программа должна парсить строку с адресом электронной почты. Есть две возможности ввести адрес электронной почты. Либо с псевдонимом или без него, однотонные электронной почты-адрес.

1-Я возможность:

string addressWithAlias = "test my address <bla@blub.com>";

2-Я возможность:

string addressWithoutAlias = "bla@blub.com";

Итак, я написал две функции:

private static string[] getAddressPartsRegex(string address)
{
    string plainaddress = address.Trim();

    Regex reg = new Regex(@"(.+?(?=<))<(.*@.*?)>");
    var gr = reg.Match(plainaddress).Groups;

    return gr.Count == 1 
        ? new[] { plainaddress } 
        : new[] { gr[1].Value.Trim(), gr[2].Value.Trim() };
}

private static string[] getAddressParts(string address)
{
    var splittedAdress = address.Split(' ');
    return splittedAdress.Last().Trim().StartsWith("<") 
        ? new[] { string.Join(" ", splittedAdress.Take(splittedAdress.Length - 1)), splittedAdress.Last().Trim(' ', '<', '>') }
        : splittedAdress;
}

Они оба прекрасно работают, и результаты такие же. Один использует регулярное выражение, другие использует Split и Join. Что бы вы предложили использовать, и почему? Что является более красивым функцию? Существуют ли какие-либо ошибки я не вижу?



Комментарии
2 ответа

Рассмотреть вопрос об использовании существующих возможностей, которые могут обеспечить дополнительный уровень проверки.

в основном System.Net.Mail.MailAddress

Также как уже упоминалось в комментариях, не нужно создавать регулярное выражение каждый раз, когда функция вызывается.

static Regex mailExpression = new Regex(@"(.+?(?=<))<(.*@.*?)>");
private static MailAddress getAddress(string address) {
if (address == null) throw new ArgumentNullException("address");
if (string.IsNullOrWhiteSpace(address)) throw new ArgumentException("invalid address", "address");

var plainaddress = address.Trim();
var groups = mailExpression.Match(plainaddress).Groups;

return groups.Count == 1
? new MailAddress(plainaddress)
: new MailAddress(groups[2].Value.Trim(), groups[1].Value.Trim());
}

По данным исходный код, внутренне MailAddress попытаемся разобрать адресу, указанному в нем.

Это избавляет от необходимости свернуть свой собственный парсер, так как одна уже есть из коробки, что уже было опробовано, протестировано и устойчиво.

private static MailAddress getAddress(string address) {
if (address == null) throw new ArgumentNullException("address");
if (string.IsNullOrWhiteSpace(address)) throw new ArgumentException("invalid address", "address");

address = address.Trim();
return new MailAddress(address);
}

У вас есть дополнительное преимущество иметь строго типизированные модели объектов, работать с которыми позволит вам использовать свойства.

Следующий тест устройство демонстрирует желаемое поведение.

[TestClass]
public class EmailParserTest {
[TestMethod]
public void Should_Parse_EmailAddress_With_Alias() {
//Arrange
var expectedAlias = "test my address";
var expectedAddress = "bla@blub.com";
string addressWithAlias = "test my address <bla@blub.com>";

//Act
var mailAddressWithAlias = getAddress(addressWithAlias);

//Assert
mailAddressWithAlias
.Should()
.NotBeNull()
.And.Match<MailAddress>(_ => _.Address == expectedAddress && _.DisplayName == expectedAlias);

}

[TestMethod]
public void Should_Parse_EmailAddress_Without_Alias() {
//Arrange
var addressWithoutAlias = "bla@blub.com";

//Act
var mailAddressWithoutAlias = getAddress(addressWithoutAlias);

//Assert
mailAddressWithoutAlias
.Should()
.NotBeNull()
.And.Match<MailAddress>(_ => _.Address == addressWithoutAlias && _.DisplayName == string.Empty);
;
}

private static MailAddress getAddress(string address) {
if (address == null) throw new ArgumentNullException("address");
if (string.IsNullOrWhiteSpace(address)) throw new ArgumentException("invalid address", "address");

address = address.Trim();
return new MailAddress(address);
}
}

10
ответ дан 1 марта 2018 в 02:03 Источник Поделиться

Позвольте мне предложить альтернативное регулярного выражения, которая корректно обрабатывает обоих случаях:

(.*?)<?(\b\S+@\S+\b)>?

Это регулярное выражение правильно определяет обе модели, которые вы хотите поддержать. Несколько примечательным здесь является использование \S в email-адреса, чтобы исключить пробелы, которые неправильно пустили в свой первоначально выражение. Что привело к принятию что-то вроде следующего как действительная спецификация электронной почты:

bla bla <te st@ exampl e.com>

Другое дело, что это регулярное выражение не принимает спецификации емейлов, которые не нуждаются в электронной почте, чтобы быть заключен в <>. Это происходит по тому адресу окружен границами слова (\b).

Вы должны быть в состоянии легко использовать его вот так:

static Regex mailExpression = new Regex(@"(.*?)<?(\b\S+@\S+\b)>?");
private static String[] getAddressParts(string addressSpec)
{
var groups = mailExpression.Match(addressSpec).Groups;
return groups[1] == ""
? new[] { groups[2].Value }
: new[] { groups[1].Value.Trim(), groups[2].Value };
}

Это, конечно, не исключает использование очень корректное предложение Nkosiбыл

5
ответ дан 1 марта 2018 в 03:03 Источник Поделиться