Получение результата регулярного выражения

Здравствуйте.
Вопрос похож на тот, что я недавно задавал про питон.
Есть регулярное выражение:


Но, в отличии от питона, писал я его сам. По-этому, оно, возможно, неправильное. Но, вроде, работает :man_shrugging:
Перенёс на C#:

			string text = ...;
			const string pattern = "\"videoId\".*(\".*\")|/shorts/(.*)\"";
            Regex regex = new Regex(pattern);
			MatchCollection matches = regex.Matches(text);
			if (matches.Count > 0 && matches[0].Groups.Count > 2)
			{
				string id = matches[0].Groups[2].Value;
				return id;
			}

			return null;

Как видно на скриншоте, нужное значение может оказаться то в группе 1, то в группе 2 (а может и ещё где-нибудь). А как я об этом заранее узнаю-то? :thinking: То есть, как это в коде должно быть прописано?

А как я об этом заранее узнаю-то?

Перепиши регулярное выражение, чтобы группа всегда оказывалась на одном месте (в каждой альтернативе).

Ещё про “именованные группы” прочитай.

конструкция группировки выделяет сопоставленную часть выражения и позволяет получить к ней доступ по имени или номеру:
(?<name>subexpression)

Текст похож на JSON. Его бы распарсить и брать желаемые значения, а не регуляркой искать. Для текущей регулярки можно проверять поле matches[0].Groups[i].Success, если для первой группы значение True, то брать значение первой группы, если для второй True, то значение второй группы. А лучше переписать регулярку, чтобы результат был в одной группе const string pattern = "\"(?:videoId\": \"|/shorts/)(.*)\""; (примерно так).

Если есть альтернативы, а в альтернативе есть группа, то у каждой группы свой номер, насколько понимаю.

Да, тоже хорошая идея.

Этот JSON получен через недокументированное API. Это значит, что он может (и будет) постоянно меняться. Вот я и решил, что лучше использовать регулярку. К тому же, нужное значение там присутствует сразу в нескольких местах.

Это вы про именованные группы? :thinking:

Нет, это мы про структуру самого регулярного выражения. Но именованная группа не помешает тоже.

А конкретнее? Что значит “структура”?

Так тут же выражение типа videoid ... значение ИЛИ shorts/значение.

Может проще разделить это на два выражения и по-очереди выполнять? (засунуть их в массив и цикл)

А чем так плохо?
Может и проще, но если их можно задавать несколько в одном, значит должен быть и способ получения результата. Разве нет? :thinking:

Ну если не менять выражение, то можно циклом по группам пройти :man_shrugging:
Не знаю что в C# будет в Groups когда найдена только вторая, но наверняка можно определить какие найдены. С именованными может быть удобнее.

С отдельными преимущество еще в том, что больше контроля. Например, если shorts/значение работает более надежно, чем videoid...значение, то можно начать с поиска shorts и только потом другие если не найдено. А с выражением a|b и строкой ba в первом матче будет b, тогда придется более сложно проходить по результатам, а не просто брать первый.

Еще раз. Если оставлять текущую регулярку, то можно проверять поле Success:

const string pattern = "\"videoId\".*(\".*\")|/shorts/(.*)\"";
Regex regex = new Regex(pattern);
Match match = regex.Match(text);
GroupCollection groups = match.Groups;
if (groups[1].Success)
    return groups[1].Value;
if (groups[2].Success)
    return groups[2].Value;
return null;

Или переписать регулярку, чтобы результат был в одной группе (плюс, группа именованная):

const string pattern = "\"(?:videoId\": \"|/shorts/)(?<id>.*)\"";
Regex regex = new Regex(pattern);
Match match = regex.Match(text);
Group id = match.Groups["id"];
if (id.Success)
    return id.Value;
return null;

Почему-то на сайте такой паттерн не работает :thinking: Ничего не находится :man_shrugging: А в вижуалке - да, работает.
И зачем нужно ?: я не понял :thinking:
На stackoverflow нашёл:

?: is a non capturing group.So it would not be included in the group or be used as back-reference

Но что это значит? :man_shrugging:
На сайте не вижу разницы в результатах, что с ?:, что без этого.

Ой, блин :man_facepalming: Там же слева язык можно выбирать. Опять забыл переключить на .NET. Постоянно забываю это делать.

Группа не будет добавлена в результат (не захвачена).

Не понимаю. В каком смысле не будет? :thinking: А что тогда будет вместо результата?

В результате будут только захваченные группы.

"\"(videoId\": \"|/shorts/)(.*)\"" - в результате будет 3 группы: 0я со всем найденным текстом, соответствующим регулярке; 1я с videoId или shorts; 2я с искомым id.
"\"(?:videoId\": \"|/shorts/)(?<id>.*)\"" - в результате будет 2 группы: 0я со всем найденным текстом, соответствующим регулярке; 1я с именем id с искомым id.

Всем спасибо. Стало немного понятнее. Буду дальше разбираться.