Но, в отличии от питона, писал я его сам. По-этому, оно, возможно, неправильное. Но, вроде, работает
Перенёс на 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 (а может и ещё где-нибудь). А как я об этом заранее узнаю-то? То есть, как это в коде должно быть прописано?
Текст похож на JSON. Его бы распарсить и брать желаемые значения, а не регуляркой искать. Для текущей регулярки можно проверять поле matches[0].Groups[i].Success, если для первой группы значение True, то брать значение первой группы, если для второй True, то значение второй группы. А лучше переписать регулярку, чтобы результат был в одной группе const string pattern = "\"(?:videoId\": \"|/shorts/)(.*)\""; (примерно так).
Если есть альтернативы, а в альтернативе есть группа, то у каждой группы свой номер, насколько понимаю.
Этот JSON получен через недокументированное API. Это значит, что он может (и будет) постоянно меняться. Вот я и решил, что лучше использовать регулярку. К тому же, нужное значение там присутствует сразу в нескольких местах.
Ну если не менять выражение, то можно циклом по группам пройти
Не знаю что в 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;
"\"(videoId\": \"|/shorts/)(.*)\"" - в результате будет 3 группы: 0я со всем найденным текстом, соответствующим регулярке; 1я с videoId или shorts; 2я с искомым id. "\"(?:videoId\": \"|/shorts/)(?<id>.*)\"" - в результате будет 2 группы: 0я со всем найденным текстом, соответствующим регулярке; 1я с именем id с искомым id.