Я пытаюсь найти список 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.
Regex может оказаться неподходящим инструментом для этой работы. Рассмотрите возможность использования анализатора URL-адресов (класс URI, Flurl и т. д.).
.com/)
<-- Это будет соответствовать .com/
- в то время как (/product
будет соответствовать /product
- поэтому будет соответствовать только .com//product
- а это не то, что вам нужно.
Если вы ищете решение, не использующее Regex, возможно, вам следует поискать Uri.Segments, что проще, как упоминал @gunr2171.
Это работает для меня:
(?<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
Я думаю, вы могли бы повысить производительность, если бы сузили схему до https?:// вместо использования .+?://
(особенно, если шаблон не привязан и эти URL-адреса могут встречаться в любом месте строки).
Если бы я мог, я бы предложил использовать разные инструменты для этой работы - регулярное выражение для всех - не лучший подход (иногда, возможно, действительный). Как правило, это приводит к очень нечитаемому коду, когда вы пытаетесь сделать все возможное с регулярным выражением. И я думаю, что это именно такой пример.
Мне не нравится много анализировать «хорошо известные» вещи, такие как 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);
}
}
Использование
.*
после.com
, скорее всего, вызовет у вас проблемы.