Захват повторенной группы

Я пытаюсь проанализировать строку, как показано ниже, используя регулярное выражение .NET:

H3Y5NC8E-TGA5B6SB-2NVAQ4E0

и верните следующее с помощью Split: H3Y5NC8E TGA5B6SB 2NVAQ4E0

Я проверяю каждый символ по определенному набору символов (обратите внимание, что буквы «I», «O», «U» и «W» отсутствуют), поэтому использование string.Split не вариант. Количество символов в каждой группе может варьироваться, и количество групп также может варьироваться. Я использую следующее выражение:

([ABCDEFGHJKLMNPQRSTVXYZ0123456789]{8}-?){3}

Это будет соответствовать ровно 3 группам по 8 символов в каждой. Любой более или менее провалит матч. Это работает, если оно правильно соответствует входным данным. Однако когда я использую метод Split для извлечения каждой группы символов, я просто получаю последнюю группу. RegexBuddy жалуется, что я повторил саму группу захвата и что я должен создать группу захвата вокруг повторной группы. Однако ни одна из моих попыток сделать это не достигла желаемого результата. Я пытался выражения как это:

(([ABCDEFGHJKLMNPQRSTVXYZ0123456789]{8})-?){4}

Но это не работает.

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


Обратите внимание, что набор символов не включает в себя весь алфавит. Это часть системы активации продукта. Таким образом, любые символы, которые могут быть случайно интерпретированы как числа или другие символы, удаляются. Например, буквы «I», «O», «U» и «W» не входят в набор символов.

Дефисы необязательны, так как пользователю не нужно вводить их сверху, но они могут быть там, если пользователь сделал копирование и вставку.

25.08.2008 01:59:45
9 ОТВЕТОВ

Зачем использовать Regex? Если группы всегда разделяются на -, вы не можете использовать Split ()?

0
25.08.2008 02:06:33

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

Dim stringArray As Array = someString.Split("-")
0
25.08.2008 02:09:28

Вы можете использовать этот шаблон:

Regex.Split("H3Y5NC8E-TGA5B6SB-2NVAQ4E0", "([ABCDEFGHJKLMNPQRSTVXYZ0123456789]{8}+)-?")

Но вам нужно будет отфильтровать пустые строки из результирующего массива. Цитата из MSDN :

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

0
25.08.2008 03:24:05

Каковы определяющие характеристики действительного блока? Нам нужно знать это, чтобы быть по-настоящему полезным.

Мое общее предложение: сначала проверьте кодировку, затем разбейте и проанализируйте отдельным методом в зависимости от того, что вы ожидаете. Если это на веб-сайте / в приложении, то вы можете использовать проверку ASP Regex на внешнем интерфейсе, а затем разбить его на внутреннем.

0
25.08.2008 02:51:18

Изучив ваш вопрос и ответы, я придумал следующее:

RegexOptions options = RegexOptions.None;
Regex regex = new Regex(@"([ABCDEFGHJKLMNPQRSTVXYZ0123456789]{8})", options);
string input = @"H3Y5NC8E-TGA5B6SB-2NVAQ4E0";

MatchCollection matches = regex.Matches(input);
for (int i = 0; i != matches.Count; ++i)
{
    string match = matches[i].Value;
}

Поскольку "-" является необязательным, вам не нужно его включать. Я не уверен, для чего вы использовали {4} в конце? Это найдет совпадения на основе того, что вы хотите, а затем с помощью MatchCollection вы можете получить доступ к каждому совпадению, чтобы перестроить строку.

3
25.08.2008 03:51:21

Если вы просто проверяете значение группы с помощью group (i) .value, то вы получите только последнее. Однако, если вы хотите перечислить все времена, когда группа была захвачена, используйте group (2) .captures (i) .value, как показано ниже.

system.text.RegularExpressions.Regex.Match("H3Y5NC8E-TGA5B6SB-2NVAQ4E0","(([ABCDEFGHJKLMNPQRSTVXYZ0123456789]+)-?)*").Groups(2).Captures(i).Value
0
25.08.2008 02:57:23

Майк,

Вы можете использовать набор символов по вашему выбору внутри группы символов. Все, что вам нужно, это добавить модификатор «+» для захвата всех групп. Смотрите мой предыдущий ответ, просто измените [A-Z0-9] на все, что вам нужно (например, [ABCDEFGHJKLMNPQRSTVXYZ0123456789])

0
25.08.2008 02:57:40
РЕШЕНИЕ

Я обнаружил ответ, который я получил после. Вот мой рабочий код:

    static void Main(string[] args)
    {
        string pattern = @"^\s*((?<group>[ABCDEFGHJKLMNPQRSTVXYZ0123456789]{8})-?){3}\s*$";
        string input = "H3Y5NC8E-TGA5B6SB-2NVAQ4E0";
        Regex re = new Regex(pattern);
        Match m = re.Match(input);

        if (m.Success)
            foreach (Capture c in m.Groups["group"].Captures)
                Console.WriteLine(c.Value);
    }
3
25.08.2008 03:33:47

Кстати, вы можете заменить класс символов [ABCDEFGHJKLMNPQRSTVXYZ0123456789] на более читаемый класс вычитаемых символов.

[[A-Z\d]-[IOUW]]

Если вы просто хотите сопоставить 3 группы таким образом, почему бы вам не использовать этот шаблон 3 раза в своем регулярном выражении и просто использовать захваченные 1, 2, 3 подгруппы для формирования новой строки?

([[A-Z\d]-[IOUW]]){8}-([[A-Z\d]-[IOUW]]){8}-([[A-Z\d]-[IOUW]]){8}

В PHP я бы вернулся (я не знаю .NET)

return "$1 $2 $3";
5
25.08.2008 12:06:53