我需要一种用于生成正则表达式的算法,该算法将检查数字是否在特定范围内。一般来说,我有以下要求:
可能的浮点格式:+ X.YYY,+ X.YY,+ X.Y,-X.YYY,-X.YY,-X.Y
X代表任意数量的数字,而Y恰好代表一位数字。至少需要一位小数。所以1应该是1.0,0应该是0.0,依此类推。
最小和最大将始终具有相同的格式。因此,您可以让min = + 2.22,max = +3.45并检查+1.541,但不能让min = + 2.223,max = +3.45并检查+1.541
下面您可以找到范围的示例:
我对正则表达式不是很熟悉,更确切地说,我什至不知道我应该从哪里开始。将不胜感激任何建议!
我的想法
我的想法是创建子范围。所以说我要检查范围7.5-222.1。然后,我相信我应该创建子范围并进行检查。例如:
答案 0 :(得分:2)
正则表达式并不真正适合测试数字是否在一定范围内;他们会变得很长。
下面是用可运行的JavaScript代码段编写的解决方案。您可以在输入框中输入范围和测试值,并同时显示生成的正则表达式和测试值的验证结果。
以下假设/规则适用:
_^
,这将使所有测试值失败。 +
是不允许的;非负数不应带有符号-0.0
是不允许的;零不应该有一个符号.9
是不允许的;小数点前至少应有一位数字
// 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>