Регулярные выражения не очень подходят для проверки, находится ли число в некотором диапазоне;они могут быть довольно длинными.
Ниже приведено решение, написанное в исполняемом фрагменте 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>