Предварительное утверждение как условие в условном подшаблоне регулярного выражения .NET - PullRequest
1 голос
/ 27 января 2012

У меня есть этот огромный RegEx для сопоставления номеров кредитных карт. Но его PCRE. Работает безупречно в PHP.

/(\d{13,16})(?(?=<)<|["']).*?(?=(?(?=>)>|["\'])\d{3,4}(?(?=<)<|["']))(?(?=>)>|["'])(\d{3,4})(?(?=<)<|["'])/is
// /i = ignore case
// /s = treat the subject as a single line

Я конвертирую его в .NET. Просто добавьте @ в начале и удвойте двойные кавычки. Я думаю, что это правильная процедура.

@"(\d{13,16})(?(?=<)<|[""]).*?(?=(?(?=>)>|[""])\d{3,4}(?(?=<)<|[""]))(?(?=>)>|[""])(\d{3,4})(?(?=<)<|[""])"

Теперь это не соответствует. Я знаю, что реализация PCRE и .NET может не совпадать. Но я думаю, что смогу преобразовать его в совместимый. Я смотрю на MSDN ссылка . Кажется, в моем паттерне нет ничего особенного, что могло бы быть специфичным для PCRE.

После анализа шаблона я обнаружил, что (?(?=<)<|[""]) не соответствует !. Так что регулярное выражение стало проще. Его сейчас @"(?(?=q)qu|\w)\w+". И я сопоставляю против "Queen, Quick, Qi etc"

PHP

Код

$data =  "Queen, Quick, Qi etc";
$pattern = "(?(?=q)qu|\w)\w+";
preg_match_all("/$pattern/is", $data, $matches);
print_r($matches);

выход

Array
(
    [0] => Array
        (
            [0] => Queen
            [1] => Quick
            [2] => etc
        )
)

C # .NET

код

        string data = "Queen, Quick, Qi etc";
        string pattern = @"(?(?=q)qu|\w)\w+";
        Regex re = new Regex(pattern, RegexOptions.IgnoreCase | RegexOptions.Singleline);

        foreach (Match m in re.Matches(data))
        {
            if (m.Success)
            {
                //Console.WriteLine("Credit Card Number={0}, CCV={1}", m.Groups[1].Value, m.Groups[6].Value);
                for (int i = 1; i < m.Groups.Count; i++)
                {
                    Console.WriteLine("[{0}][{1}]", i, m.Groups[i].Value);
                    for (int j = 0; j < m.Groups[i].Captures.Count; j++)
                    {
                        Console.WriteLine("[{0}][{1}][{2}]", i, m.Groups[i].Value, m.Groups[i].Captures[j].Value);
                    }
                }
            }
        }

выход

Press any key to continue . . .

Вывод - ничто.

Мои вопросы

  1. Работает ли упреждающее утверждение как условие в условном под-шаблоне с регулярным выражением .NET?
  2. Как я могу изменить более простое регулярное выражение @"(?(?=q)qu|\w)\w+", чтобы оно совпадало с PHP в .NET?
  3. На первом регулярном выражении (огромном) в .NET есть что-нибудь, что я могу применить, чтобы оно соответствовало так же, как PHP?

Спасибо

1 Ответ

2 голосов
/ 27 января 2012

1 .: Условные выражения работают в .NET так же, как в PHP.

2 .: «Более простое» регулярное выражение подходит для .NET. Вы просто используете это неправильно:

В вашем регулярном выражении нет групп захвата. Это означает, что цикл

for (int i = 1; i < m.Groups.Count; i++) {...}

никогда не выполняется, потому что m.Groups.Count равно 1.

Правильный путь будет что-то вроде

foreach (Match m in re.Matches(data))
{
   if (m.Success)
   {
       for (int i = 0; i < m.Groups.Count; i++) // Groups are numbered from zero
       {
           // Groups[0] is the entire match
           Console.WriteLine("[{0}][{1}]", i, m.Groups[i].Value);
       }
   }
} 

3 .: В вашем регулярном выражении отсутствуют одинарные кавычки.

Regex regexObj = new Regex(@"(\d{13,16})(?(?=<)<|[""']).*?(?=(?(?=>)>|[""'])\d{3,4}(?(?=<)<|[""']))(?(?=>)>|[""'])(\d{3,4})(?(?=<)<|[""'])", RegexOptions.Singleline);

будет буквальный перевод.

4 .: Вам не нужен параметр /i или Ignorecase, так как в вашем регулярном выражении нет букв.

5 .: (?(?=<)<|["']) не имеет смысла. Он совпадает с тем же текстом, что и [<"']. В конце концов это означает «если есть <, то соответствует <. В противном случае, попробуйте сопоставить " или '. Нет необходимости использовать условное регулярное выражение вообще.

Таким образом, все регулярное выражение может быть упрощено до

(\d{13,16})[<"'].*?(?=[>"']\d{3,4}[<"'])[>"'](\d{3,4})[<"']

6 .: Это более четко показывает еще одну лишнюю часть регулярного выражения: у вас есть предварительное утверждение (?=[>"']\d{3,4}[<"']), за которым следует точно такое же регулярное выражение [>"'](\d{3,4})[<"'], поэтому его можно полностью отбросить.

Конечный результат:

(\d{13,16})[<"'].*?[>"'](\d{3,4})[<"']

или, в C #:

Regex regexObj = new Regex(@"(\d{13,16})[<""'].*?[>""'](\d{3,4})[<""']", RegexOptions.Singleline);
...