Проблема с диапазонами в регулярном выражении - PullRequest
0 голосов
/ 28 февраля 2019

Я пытаюсь создать регулярное выражение, которое проверяет следующий формат:

  • будут разделены только числа, или -
  • могут быть диапазоны чисел (разделенные -)
  • числа должны быть от 1 до 31
  • значение второй части больше, чем первой в диапазоне (это более сложно, но если это оченьтрудно, я откажусь от него)

Пример, который я считаю верным:

4,31,2-22,8
29,1-10,2-12,9

Пример, который я бы счел недействительным:

4,31,2-22,8,
29,1-10, -2-12-, 9
29,1-50,12-2,32

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

(((1[0-9]|2[0-9]|3[0-1]|[1-9])(\-(1[0-9]|2[0-9]|3[0-1]|[1-9]))?)(\,((1[0-9]|2[0-9]|3[0-1]|[1-9])(\-(1[0-9]|2[0-9]|3[0-1]|[1-9]))?))*)

Atв тот момент, когда это выражение хорошо воспринимает меня как «-» и «,», и числа идут от 1 до 31. Проблема ранга в том, что второе значение больше первого, я понятия не имею, как его решить. Есть предложения?

Ответы [ 2 ]

0 голосов
/ 28 февраля 2019

Я думаю, что лучше всего сделать это с помощью регулярного выражения и обычного кода.Эта функция проверяет, соответствует ли вся строка шаблону чисел или диапазонов, разделенных запятыми, затем извлекает отдельные числа или диапазоны и применяет к ним другую проверку ошибок (от 1 до 31, конец> = начало):

function validate_range($range) {
    if (!preg_match('/^((\d+(?:-\d+)?)(?:,(?!$)|$))+$/', $range)) return false;
    preg_match_all('/(\d+(?:-\d+)?)/', $range, $matches);
    foreach ($matches[1] as $match) {
        if (strpos($match, '-') !== false) {
            list($start, $end) = explode('-', $match);
            if ($end < $start) return false;
            if ($start < 1 || $start > 31 || $end < 1 || $end > 31) return false;
        }
        if ($match < 1 || $match > 31) return false;
    }
    return true;
}

Вы можете проверить это так:

$ranges = array(
    '4,31,2-22,8',
'29,1-10,2-12,9',
'4,31,2-22,8,',
'29,1-10,-2-12-,9',
'29,1-50,12-2,32');
foreach ($ranges as $range) {
    if (validate_range($range)) 
        echo "$range is OK!\n";
    else
        echo "$range is no good\n";
}

Вывод:

4,31,2-22,8 is OK!
29,1-10,2-12,9 is OK! 
4,31,2-22,8, is no good 
29,1-10,-2-12-,9 is no good 
29,1-50,12-2,32 is no good

Демонстрация на 3v4l.org

0 голосов
/ 28 февраля 2019

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

Решение гораздо проще, чем кажется:

function isValid($string)
{
    $numbers = explode(',', $string);

    // Covers the case when you have an empty value at the beginning/end of string.
    if (count($numbers) !== count(array_filter($numbers))) {
        return false; 
    }

    foreach ($numbers as $number) {
        if (is_numeric($number) && $number >= 1 && $number <= 31) {
            continue;
        }

        if (!preg_match('/^(\d+)-(\d+)$/', $number, $matches)) {
            return false;
        }

        if ($matches[1] >= 1 && $matches[1] <= 31 && 
            $matches[2] >= 1 && $matches[2] <= 31 && 
            $matches[2] > $matches[1]
        ) {
            continue;
        }

        return false;
    }

    return true;
}

$strings = [
    '4,31,2-22,8',
    '29,1-10,2-12,9',
    '4,31,2-22,8,',
    '29,1-10,-2-12-,9',
    '29,1-50,12-2,32',
];


foreach ($strings as $string) {
    var_dump(isValid($string));
}

Результаты будут:

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