Regex соответствует определенным шаблонам URL-адресов

Я пытаюсь найти список URL-адресов, соответствующих шаблону. У меня есть строка с примечанием, которая включает несколько URL-адресов с разными шаблонами.

Пример заметки:

This is the list of link you need to solve the problem
http://customdomain.com/product/123 *new product*
https://customdomain.com/invoice/987
https://customdomain.com/product/45 (product to remove)
https://customdomain.com/product/999 
http://customdomain.com/invoice/741

Это мой код C# для получения списка URL-адресов продуктов:

var pattern = @"(((http|https)://customdomain\.com/).*(/product/)(\d+))";
MatchCollection matches = Regex.Matches(text, pattern);

Я хочу получить список из 3 доменов продуктов, и результат совпадений только 1.

🤔 А знаете ли вы, что...
C# поддерживает множество парадигм программирования, включая процедурное, объектно-ориентированное и функциональное программирование.


66
2

Ответы:

Решено

Это работает для меня:

(?<scheme>.+?://)(?<host>[0-9a-z\-\.]+)(?<path>/product/(?<pid>\d+))

Вам нужно будет запустить его в режиме без учета регистра (т. е. с RegexOptions.IgnoreCase).

Демо: https://regex101.com/r/wDoIg6/2


const String INPUT_TEXT = @"

http://customdomain.com/product/123  *new product*
https://customdomain.com/invoice/987
https://customdomain.com/product/45 (product to remove)
https://customdomain.com/product/999 
http://customdomain.com/invoice/741

";

Regex regex = new Regex( @"(?<scheme>.+?://)(?<host>[0-9a-z\-\.]+)(?<path>/product/(?<pid>\d+))", RegexOptions.IgnoreCase | RegexOptions.Compiled );

MatchCollection matches = regex.Matches( INPUT_TEXT );
foreach( Match m in matches )
{
    Console.WriteLine(
        "{0}{1}{2} - {3}",
        /*0:*/ m.Groups["scheme"].Value,
        /*1:*/ m.Groups["host"  ].Value,
        /*2:*/ m.Groups["path"  ].Value,
        /*3:*/ m.Groups["pid"   ].Value
    );
}

Дает мне этот вывод:

http://customdomain.com/product/123 - 123
https://customdomain.com/product/45 - 45
https://customdomain.com/product/999 - 999

Если бы я мог, я бы предложил использовать разные инструменты для этой работы - регулярное выражение для всех - не лучший подход (иногда, возможно, действительный). Как правило, это приводит к очень нечитаемому коду, когда вы пытаетесь сделать все возможное с регулярным выражением. И я думаю, что это именно такой пример.

Мне не нравится много анализировать «хорошо известные» вещи, такие как URL-адреса, HTML, XML и т. д.

Я бы ограничил регулярное выражение тем, что ему действительно нужно делать, поэтому извлекаю из вашей заметки «кандидатов» для URL-адресов.

Для этого мы можем использовать шаблон https?://\S+:

  • http часть соответствует http буквально,
  • s? соответствует s, но необязательно,
  • :// соответствует :// буквально,
  • \S+ соответствует одному или нескольким символам без пробелов (читается до конца URL).

Таким образом, мы извлекаем cnadidates URL-адресов, которые затем пытаемся проанализировать как Uri с помощью его конструктора — имея это, мы позже можем использовать класс Uri для обработки (извлечения пути и т. д.).

Полный пример:

public static void Main(string[] args)
{
    var note = @"This is the list of link you need to solve the problem
http://customdomain.com/product/123 *new product*
https://customdomain.com/invoice/987
https://customdomain.com/product/45 (product to remove)
https://customdomain.com/product/999 
http://customdomain.com/invoice/741";

    var simpleRegex = @"https?://\S+";
    var matched = Regex.Matches(note, simpleRegex);
    var productUrls = new List<Uri>();
    foreach (Match match in matched)
    {
        var validUri = new Uri(match.Value);
        var localPathParts = validUri.LocalPath.Split('/');
        if (localPathParts.Contains("product"))
            productUrls.Add(validUri);
    }
}