Алгоритм генерации регулярного выражения для проверки, находится ли число в диапазоне (ЛЮБОЙ ДИАПАЗОН) - PullRequest
0 голосов
/ 07 марта 2019

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

  • Мне нужно использовать регулярное выражение
  • Регулярное выражение необходимо генерировать на основе заданных чисел (мин. И макс.)
  • Требуется только проверкадля чисел с плавающей запятой
  • Числа могут быть как положительными, так и отрицательными
  • Возможные форматы с плавающей запятой: + X.YYY, + X.YY, + XY, -X.YYY, -X.YY, -XY

    X обозначает любое количество цифр, а Y обозначает ровно одну цифру.Требуется хотя бы один десятичный знак.Таким образом, 1 должно быть 1,0, 0 должно быть 0,0 и так далее.

    Мин и макс всегда будут иметь одинаковый формат.Таким образом, вы можете иметь min = +2,22, max = +3,45 и проверить на +1,541, но вы не можете иметь min = +2,223, max = +3,45 и проверить на + 1,514

Ниже васможно найти примеры диапазонов:

  • от +1,0 до + 20,0
  • от -1,0 до + 20,0
  • от -20,0 до -10,0
  • с +1.01 до + 2.12

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

МОЯ ИДЕЯ

У меня есть идея создать поддиапазоны.Скажем, я хочу проверить диапазон 7.5 - 222.1.Тогда я считаю, что я должен создать поддиапазоны и проверить их.Например:

  • 7,5 - 7,9
  • 8,0 - 9,9
  • 10,0 - 99,9
  • 100,0 - 222,0
  • 222,0 -222,1

1 Ответ

2 голосов
/ 08 марта 2019

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

Ниже приведено решение, написанное в исполняемом фрагменте JavaScript.Вы можете ввести диапазон и тестовое значение в поля ввода, и отобразятся как произведенное регулярное выражение, так и результат проверки для тестового значения.

Применяются следующие допущения / правила:

  • Когдадиапазон недействителен (например, минимальное число больше максимального), тогда регулярное выражение будет _^, что приведет к сбою всех тестовых значений.
  • Испытательные значения должны иметь такое же количество десятичных цифр, что и минимальное / максимальное значения.
  • Когда минимальное и максимальное значения имеют различное количество десятичных цифр, применяется большее из двух
  • + не допускается;неотрицательные числа не должны иметь знак
  • -0.0 не допускается;ноль не должен иметь знак
  • .9 не допускается;перед десятичной точкой должна быть хотя бы одна цифра
  • Правила для минимальных / максимальных значений менее строгие.
  • минимум и максимум не обязательно должны иметь одинаковое количество целых цифр.Например, диапазон от -33,08 до 12328,84 будет работать нормально.

// Some helper constants/functions for producing regex
const reDot = "\\.";

function reRange(low, high) {
    return high-low === 9 ? "\\d" : low<high ? "[" + low + "-" + high + "]" : low;
}

function reRepeat(what, min, max=min) {
    return !max ? ""
        : what + (max > 1 ? "{" + min + (min < max ? "," + max : "") + "}" : min ? "" : "?");
}

function reOr(list) {
    return list.length > 1 ? "(" + list.join("|") + ")" : list[0];
}

function reAnchor(what) {
    return "^" + what + "$";
}

// Main function:
function rangeRegex(min, max) {
    if (!(+min <= +max)) return "_^"; // All strings should fail this regex
    const decimals = Math.max( (min+".").split(".")[1].length, (max+".").split(".")[1].length );
    // Take care of negative ranges:
    if (+min < 0 && +max < 0) return reAnchor("-" + positiveRange(-max, -min));
    if (+min < 0) return reAnchor(reOr(["-(?=.*[1-9])" + positiveRange(0, -min), positiveRange(0, max)]));
    return reAnchor(positiveRange(min, max));
    
    function positiveRange(min, max) {
        // Format the two input numbers with equal number of decimals and remove decimal point
        const minParts = (Math.abs(min)+".").split(".");
        const maxParts = (Math.abs(max)+".").split(".");
        min = minParts[0] + minParts[1].padEnd(decimals, "0"); 
        max = maxParts[0] + maxParts[1].padEnd(decimals, "0");
        // Build regex parts
        const parts = [];
        if (min.length < max.length && !/^1?0*$/.test(min)) {
            parts.push(fixedLengthRange(min, "9".repeat(min.length)));
            min = "1" + "0".repeat(min.length);
        }
        if (min.length < max.length && !/^9+$/.test(max)) {
            parts.push(fixedLengthRange("1" + "0".repeat(max.length-1), max));
            max = "9".repeat(max.length-1);
        }
        if (/^1?0*$/.test(min) && /^9+$/.test(max)) {
            parts.push(
                reRange(min[0], 9) 
                    + reRepeat(reRange(0, 9), min.length-decimals-1, max.length-decimals-1)
                    + (decimals ? reDot + reRepeat(reRange(0, 9), decimals) : "") 
            );
        } else {
            parts.push(fixedLengthRange(min, max));
        }
        return reOr(parts);
    }
    
    function fixedLengthRange(min, max) {
        const len = max.length;
        if (!len) return "";
        const pre = len === decimals ? reDot : "";
        let low = +min[0];
        let high = +max[0];
        if (low === high) return pre + min[0] + fixedLengthRange(min.slice(1), max.slice(1));
        const parts = [];
        if (+min.slice(1)) {
            parts.push(min[0] + fixedLengthRange(min.slice(1), "9".repeat(len-1)));
            low++;
        }
        if (max.slice(1) < "9".repeat(max.length-1)) {
            parts.push(max[0] + fixedLengthRange("0".repeat(len-1), max.slice(1)));
            high--;
        }
        if (low <= high) {
            parts.push(reRange(low, high) + 
                (len <= decimals || !decimals ? reRepeat(reRange(0, 9), len-1)
                : reRepeat(reRange(0, 9), len-1-decimals) + reDot + reRepeat(reRange(0, 9), decimals)));
        }
        return pre + reOr(parts);
    }
}

// I/O handling for this snippet

const inputMin = document.querySelector("#min");
const inputMax = document.querySelector("#max");
const inputVal = document.querySelector("#val");
const outputRegex = document.querySelector("#regex");
const outputValid = document.querySelector("#valid");

document.oninput = function() {
    const regex = rangeRegex(inputMin.value, inputMax.value);
    outputRegex.textContent = regex;
    outputValid.textContent = new RegExp(regex).test(inputVal.value) ? "OK" : "Not OK";
}
<label>Min: <input id="min"></label>
<label>Max: <input id="max"></label>
<hr>
<div>Regex: <span id="regex"></span></div>
<label>Test: <input id="val"></label>
<div>Valid: <span id="valid"></span></div>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...