Существует ли RegEx, который может анализировать самый длинный список цифр из строки? - PullRequest
2 голосов
/ 19 марта 2011

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

Некоторые примеры:

0001          - No prefix, Number = 0001, No suffix
1-0001        - Prefix = 1-, Number = 0001, No suffix
AAA001        - Prefix = AAA, Number = 001, No suffix
AAA 001.01    - Prefix = AAA , Number = 001, Suffix = .01
1_00001-01    - Prefix = 1_, Number = 00001, Suffix = -01
123AAA 001_01 - Prefix = 123AAA , Number = 001, Suffix = _01

Строки могут поставляться с любой смесью префиксов и суффиксов, но ключевым моментом является то, что часть Number - это всегда самый длинный последовательный список цифр.

Я пробовал различные RegEx, которые работают с большинством, но не со всеми этими примерами. Возможно, я что-то упустил, или, возможно, в этом случае RegEx не правильный путь?

(RegEx должен быть .NET-совместимым)

ОБНОВЛЕНИЕ : Для тех, кто заинтересован, вот код C #, который я придумал:

var regex = new System.Text.RegularExpressions.Regex(@"(\d+)");
if (regex.IsMatch(m_Key)) {
     string value = "";
     int length;
     var matches = regex.Matches(m_Key);
     foreach (var match in matches) {
         if (match.Length >= length) {
             value = match.Value;
             length = match.Length;
         }
     }
     var split = m_Key.Split(new String[] {value}, System.StringSplitOptions.RemoveEmptyEntries);
     m_KeyCounter = value;
     if (split.Length >= 1) m_KeyPrefix = split(0);
     if (split.Length >= 2) m_KeySuffix = split(1);
}

Ответы [ 4 ]

3 голосов
/ 19 марта 2011

Вы правы, эта проблема не может быть решена чисто регулярными выражениями. Вы можете использовать регулярные выражения для "токенизации" (лексического анализа) входных данных, но после этого вам потребуется дополнительная обработка (синтаксический анализ).

Так что в этом случае я бы токенизировал входные данные с помощью (например) простого поиска по регулярному выражению (\d+) и затем обрабатывал токены (анализ). Для этого нужно увидеть, длиннее ли текущий токен, чем токены, которые были до него.

Чтобы лучше понять класс задач, которые регулярные выражения «решают», и когда требуется синтаксический анализ, вы можете проверить общую теорию компилятора, особенно когда регулярные выражения используются при построении компилятора (например, http://en.wikipedia.org/wiki/Book:Compiler_construction).

1 голос
/ 19 марта 2011

Вы вводите не регулярно, поэтому регулярное выражение не подойдет. Я бы перебрал все группы цифр через (\ d +) и нашел бы самое длинное, а затем построил бы новое регулярное выражение в форме (.*)<number>(.*), чтобы найти ваш префикс / суффикс.

Или, если вам удобны строковые операции, вы, вероятно, можете просто найти начало и конец целевой группы и использовать substr для поиска исправления pre / suf. * ​​1004 *

0 голосов
/ 19 марта 2011

Это полностью зависит от вашего движка Regexp.Проверьте свою среду Regexp на предмет захвата, в ней может быть что-то вроде автоматических переменных в Perl.

ОК, давайте поговорим о вашем вопросе:

Имейте в виду, что и NFA, и DFAпочти все движки Regexp являются жадными, это означает, что (\d+) всегда найдет самое длинное совпадение, когда оно «споткнется» над ним.

Теперь, что я могу получить из вашего примера, это вывсегда нужна средняя часть числа, попробуйте это:

/^(.*\D)?(\d+)(\D.*)?$/ig

Теперь посмотрите на переменные $1, $2, $3.Не все из них будут существовать: если их все три, $2 будет содержать ваш номер, остальные переменные, части префикса.когда один из префиксов отсутствует, будут установлены только переменные $1 и $2, вы должны убедиться, какой из них является целым числом.Если префикс и суффикс отсутствуют, $1 будет содержать число.

Идея состоит в том, чтобы заставить двигатель "спотыкаться" по первым нескольким символам и начинать совпадение с длинным числом в середине.

Поскольку присутствует модификатор /g, вы можете перебрать все доступные комбинации, которые машина найдет, затем вы можете просто выбрать ту, которая вам больше всего нравится или что-то еще.

Этот пример в PCRE,но я уверен. .NET имеет совместимый режим.

0 голосов
/ 19 марта 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...