Глобальное сопоставление регулярных выражений с остановкой в середине строки

1

Я пытаюсь извлечь группы чисел из строки. Эти цифры могут быть как сами по себе, так и в виде диапазона в формате \d+ - \d+, в то время как индикатор диапазона между двумя номерами может меняться, и цифры могут иметь префикс M- или STR. Эти группы могут встречаться от 1 до n раз в заданной строке, но соответствие должно прекращаться, если за группой следует какой-либо символ, который не является числом, пробелом или одним из префиксов, упомянутых выше, даже если после этого можно найти дальнейшие номера.

В качестве примера, следующие строки

01
05,07
05, 7
M-01, M-12
311,STR 02
M-56
STR 17
01 - Random String 25-31 Random other string
M-04 Random String 01
M-17,3,148,14 to 31
M-17,3,STR 148,14 to 31 - Random String
M-17,3,148,14- 31 Random, String 02 Random, other string
STR 17,3,12 to 18, 148 ,M-14- 31 : Random String 02

Должен вернуться

01
05;07
05;7
01;12
311;02
56
17
01
04
17;3;148;14 to 31
17;3;148;14 to 31
17;3;148;14- 31
17;3;12 to 18;148;14- 31

Я использую javascript и могу получить правильный результат, выполнив

var pattern = /(\d+)\s?(?:-|~|to)?\s?(\d+)?/ig
while (result = pattern.exec(line)) {console.log(result)}

но я не могу понять, как не соответствовать числам после первой строки, т.е. M-17,3,148,14 to 31 - Random string 46 Random string вернет значения 17;3;148;14 to 31;46 M-17,3,148,14 to 31 - Random string 46 Random string 17;3;148;14 to 31;46, в то время как 46 не должны совпадать.

Я не очень обеспокоен форматом результатов, так как я все равно их дезинфицирую, поэтому не имеет значения, возвращается ли '03 ' как '03' или '03' '03 '. Это также верно для диапазонов чисел, 15 - 17 может быть возвращено как 15 - 17 или, как в приведенном выше примере, использовать группы захвата для определения верхней и нижней границы, но мне все еще нужно знать, являются ли два числа отдельный или диапазон, поэтому 5,8,10-12 не могут быть возвращены как 5;8;10;12.

Моя конечная цель - извлечь все возможные значения в каждой строке. После того, как я извлек все диапазоны чисел, я прохожу через каждый результат, чтобы получить все возможные значения, например, 5,8,10-12 станет 5; 8; 10; 11; 12.

Если это возможно, и это чисто необязательно, я также хотел бы сохранить строку после последнего диапазона чисел, например STR 14, 23 Some String 18 Some other string должна вернуться в 14;23 и отдельно. Some String 18 Some other string.

Буду признателен, если кто-нибудь поймет, как это решить.

Теги:

2 ответа

0
Лучший ответ

Вот моя попытка.

[
    '01',
    '05,07',
    '05, 7',
    'M-01, M-12',
    '311,STR 02',
    'M-56',
    'STR 17',
    '01 - Random String 25-31 Random other string',
    'M-04 Random String 01',
    'M-17,3,148,14 to 31',
    'M-17,3,STR 148,14 to 31 - Random String',
    'M-17,3,148,14- 31 Random, String 02 Random, other string',
    'STR 17,3,12 to 18, 148 ,M-14- 31 : Random String 02',
    '14 ~ 16',
    'Random String 15',
    '1to3',
    'M-01 to STR 6',
    '17 56'
].forEach(function(str) {
    var rangeRe = /(?:\s*,\s*)(?:M-|STR )?(\d+)(?:\s*(?:-|~|to)\s*(\d+))?/g,
        ranges = [],
        lastIndex = 1,
        match;

    str = ',' + str;

    while (match = rangeRe.exec(str)) {
        // Push a lower and upper bound onto the list of ranges
        ranges.push([+match[1], +(match[2] || match[1])]);

        lastIndex = rangeRe.lastIndex;
    }

    // Log the original string, the ranges and the remainder
    console.log([
       str.slice(1),
       ranges.map(function(pair) {
           return pair[0] + '-' + pair[1];
       }).join(' ; '),
       str.slice(lastIndex)
    ]);
});

Вот правила, которыми я придерживался:

  • Числа состоят из последовательных цифр.
  • Диапазон состоит либо из одного числа, либо из пары чисел.
  • Если в диапазоне есть пара, они могут быть разделены символами -, ~ или to, плюс произвольные пробелы с обеих сторон разделителя.
  • Диапазон (диапазон нот, а не номер) может быть префикс M- или STR. Между префиксом и диапазоном не допускается никаких дополнительных пробелов.
  • Диапазоны отделены друг от друга , а также произвольные пробельные обе стороны от ,.

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

Я использовал statefulness exec. Каждая итерация цикла начинается с совпадения с предыдущим совпадением. lastIndex отслеживается так, что мы можем сгенерировать оставшуюся "случайную строку" в конце.

Я добавить , из передней части строки, прежде чем начать. Это позволяет RegExp предположить, что все диапазоны начинаются с ,, избегая необходимости в специальном случае первого диапазона.

Ключевое отличие от некоторых из RegExps, которые вы разместили, состояло в том, что я разделил раздел "разделитель диапазона и верхняя граница" как единое целое, вместо того, чтобы сделать их индивидуально необязательными. Результатом этого является то, что входной сигнал, подобный 17 56, будет рассматривать 56 как "случайную строку", а не как верхнюю границу. Диапазон будет рассматриваться как 17-17.

  • 0
    Это работает невероятно хорошо. Гораздо лучше, чем мое оригинальное решение. Большое спасибо за усилия!
0

Поэтому, получив кофе, я думаю, что я понял что-то близкое к решению:

function extractNumbers(line){
    var str = line.replace(/(?:M-\s?|STR )(\d+)/ig,'$1')
    var rightpart = str.match(/([a-x].*)/i)
    var leftpart = str.replace(rightpart[1],'')
    var pattern = /(\d+)\s?(?:-|~|to)?\s?(\d+)?/ig
    while (result = pattern.exec(leftpart)) {console.log(result)}
    console.log(rightpart[1])
}

Эта функция выводит все диапазоны чисел, а затем остальную часть строки на консоль. Есть вероятность ложных срабатываний, потому что он сначала заменяет все вхождения M- и STR, за которым следует число, даже если они встречаются в правой части строки. Шансы этой точной последовательности символов, встречающихся в правой части, вероятно, небольшие, но все же..

Если кто-то ответит на исходный вопрос или идею о том, как устранить вероятность ложных срабатываний, я бы с удовольствием это увидел.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню