Как я могу получить регулярное выражение только для добавления в коллекцию матчей?
У меня есть строка, в которой есть несколько html-комментариев. Мне нужно подсчитать уникальные соответствия выражения.
Например, строка может быть:
var teststring = "<!--X1-->Hi<!--X1-->there<!--X2-->";
В настоящее время я использую это для получения совпадений:
var regex = new Regex("<!--X.-->");
var matches = regex.Matches(teststring);
Результат этого - 3 совпадения. Тем не менее, я хотел бы, чтобы это было всего 2 матча, так как есть только два уникальных матча.
Я знаю, что могу, возможно, пропустить полученный MatchCollection и удалить дополнительный Match, но я надеюсь, что есть более элегантное решение.
Разъяснение: строка примера значительно упрощена из того, что на самом деле используется. Легко может быть X8 или X9, и в строке есть, вероятно, десятки.
Ответы
Ответ 1
Я бы просто использовал Enumerable.Distinct Method, например:
string subjectString = "<!--X1-->Hi<!--X1-->there<!--X2--><!--X1-->Hi<!--X1-->there<!--X2-->";
var regex = new Regex(@"<!--X\d-->");
var matches = regex.Matches(subjectString);
var uniqueMatches = matches
.OfType<Match>()
.Select(m => m.Value)
.Distinct();
uniqueMatches.ToList().ForEach(Console.WriteLine);
Выводит следующее:
<!--X1-->
<!--X2-->
Для регулярного выражения вы могли бы использовать этот?
(<!--X\d-->)(?!.*\1.*)
Кажется, нужно работать над вашей тестовой строкой в RegexBuddy хотя бы =)
// (<!--X\d-->)(?!.*\1.*)
//
// Options: dot matches newline
//
// Match the regular expression below and capture its match into backreference number 1 «(<!--X\d-->)»
// Match the characters "<!--X" literally «<!--X»
// Match a single digit 0..9 «\d»
// Match the characters "-->" literally «-->»
// Assert that it is impossible to match the regex below starting at this position (negative lookahead) «(?!.*\1.*)»
// Match any single character «.*»
// Between zero and unlimited times, as many times as possible, giving back as needed (greedy) «*»
// Match the same text as most recently matched by capturing group number 1 «\1»
// Match any single character «.*»
// Between zero and unlimited times, as many times as possible, giving back as needed (greedy) «*»
Ответ 2
Кажется, вы делаете две разные вещи:
- Соответствующие комментарии, такие как /< - X. → /
- Поиск набора уникальных комментариев
Поэтому вполне логично обрабатывать их как два разных шага:
var regex = new Regex("<!--X.-->");
var matches = regex.Matches(teststring);
var uniqueMatches = matches.Cast<Match>().Distinct(new MatchComparer());
class MatchComparer : IEqualityComparer<Match>
{
public bool Equals(Match a, Match b)
{
return a.Value == b.Value;
}
public int GetHashCode(Match match)
{
return match.Value.GetHashCode();
}
}
Ответ 3
Извлеките комментарии и сохраните их в массиве. Затем вы можете отфильтровать уникальные значения.
Но я не знаю, как реализовать это на С#.
Ответ 4
Захватите внутреннюю часть комментария как группу. Затем поместите эти строки в хэш-таблицу (словарь). Затем спросите словарь для его подсчета, так как он будет повторять повторные повторы.
var teststring = "<!--X1-->Hi<!--X1-->there<!--X2-->";
var tokens = new Dicationary<string, string>();
Regex.Replace(teststring, @"<!--(.*)-->",
match => {
tokens[match.Groups[1].Value] = match.Groups[1].Valuel;
return "";
});
var uniques = tokens.Keys.Count;
Используя конструкцию Regex.Replace, вы получите lambda, вызываемую для каждого совпадения. Поскольку вы не заинтересованы в замене, вы не устанавливаете его равным ни с чем.
Вы должны использовать Group [1], потому что группа [0] - это полное совпадение.
Я повторяю одно и то же с обеих сторон, так что его легче вставить в словарь, в котором хранятся только уникальные ключи.
Ответ 5
В зависимости от того, сколько у вас Xn вы могли бы использовать:
(\<!--X1--\>){1}.*(\<!--X2--\>){1}
Это будет соответствовать только каждому вхождению X1, X2 и т.д., если они приведены в порядок.