Захват повторенной группы - PullRequest
3 голосов
/ 25 августа 2008

Я пытаюсь проанализировать строку, подобную следующей, используя регулярное выражение .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» не входят в набор символов.

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

Ответы [ 9 ]

5 голосов
/ 25 августа 2008

Кстати, вы можете заменить класс символов [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";
3 голосов
/ 25 августа 2008

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

    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 августа 2008

После рассмотрения вашего вопроса и ответов я придумал:

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 вы можете получить доступ к каждому совпадению, чтобы перестроить строку.

0 голосов
/ 25 августа 2008

Mike

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

0 голосов
/ 25 августа 2008

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

system.text.RegularExpressions.Regex.Match("H3Y5NC8E-TGA5B6SB-2NVAQ4E0","(([ABCDEFGHJKLMNPQRSTVXYZ0123456789]+)-?)*").Groups(2).Captures(i).Value
0 голосов
/ 25 августа 2008

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

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

0 голосов
/ 25 августа 2008

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

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

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

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

0 голосов
/ 25 августа 2008

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

Dim stringArray As Array = someString.Split("-")
0 голосов
/ 25 августа 2008

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

...