我试图从查看站点中的某些 Logo 和链接中排除某些内部 IP 地址和某些内部 IP 地址格式。我有多个 IP 地址范围(下面给出的示例)。是否可以使用 javascript 编写一个可以匹配下面列表中的所有 IP 地址的正则表达式?
10.X.X.X
12.122.X.X
12.211.X.X
64.X.X.X
64.23.X.X
74.23.211.92
and 10 more
最佳答案
引用句点,用 \d+
替换 X,然后用竖线将它们连接在一起:
const allowedIPpatterns = [
"10.X.X.X",
"12.122.X.X",
"12.211.X.X",
"64.X.X.X",
"64.23.X.X",
"74.23.211.92" //, etc.
];
const allowedRegexStr = '^(?:' +
allowedIPpatterns.
join('|').
replace(/\./g, '\\.').
replace(/X/g, '\\d+') +
')$';
const allowedRegexp = new RegExp(allowedRegexStr);
然后你就准备好了:
'10.1.2.3'.match(allowedRegexp) // => ['10.1.2.3']
'100.1.2.3'.match(allowedRegexp) // => null
它是如何工作的:
首先,我们必须将各个 IP 模式转换为符合其意图的正则表达式。 “所有形式为‘12.122.X.X’的 IP”的正则表达式如下:
^12\.122\.\d+\.\d+$
^
表示匹配必须从字符串的开头开始;否则,112.122.X.X IP 也会匹配。12
等:数字与自身匹配\.
:正则表达式中的句点完全匹配任何字符;我们想要文字句点,所以我们在前面加一个反斜杠。\d
:[0-9]
的简写;匹配任何数字。+
:表示“1 或更多” - 在本例中为 1 或更多数字。$
:与^
类似,这意味着匹配必须在字符串末尾结束。
因此,我们将 IP 模式转换为正则表达式。对于单个模式,您可以使用如下代码:
const regexStr = `^` + ipXpattern.
replace(/\./g, '\\.').
replace(/X/g, '\\d+') +
`$`;
这只是将所有 .
替换为 \.
并将 X
替换为 \d+
并粘贴 ^
和 $
位于两端。
(注意双反斜杠;字符串解析和正则表达式解析都使用反斜杠,因此无论我们想要一个文字通过字符串解析器进入正则表达式解析器,我们都必须将其加倍。)
在正则表达式中,交替 this|that
匹配任何与 this
或 that
匹配的内容。因此,如果我们将列表转换为 re1|re2|re3|...|relast
形式的单个正则表达式,我们可以立即检查所有 IP 的匹配情况。
然后我们可以进行一些重构,使正则表达式匹配器的工作变得更容易;在这种情况下,由于所有正则表达式都将具有 ^...$
,我们可以将这些约束从各个正则表达式中移出,并将它们放在整个正则表达式中:^(10\.\d+\.\d+\.\d+|12\.122\.\d+\.\d+|...)$
。括号可防止 ^
仅成为第一个模式的一部分,并且 $
不会仅成为最后一个模式的一部分。但由于普通括号既捕获又分组,并且我们不需要捕获任何内容,因此我将它们替换为非分组版本 (?:
..)
。
在这种情况下,我们可以对巨大的字符串进行一次全局搜索和替换,而不是对每个模式单独进行一次。所以结果就是上面的代码:
const allowedRegexStr = '^(?:' +
allowedIPpatterns.
join('|').
replace(/\./g, '\\.').
replace(/X/g, '\\d+') +
')$';
这仍然只是一个字符串;我们必须将其转换为实际的 RegExp
对象才能进行匹配:
const allowedRegexp = new RegExp(allowedRegexStr);
正如所写,这不会过滤掉非法 IP - 例如,10.1234.5678.9012
将匹配第一个模式。如果要将各个字节值限制为十进制范围 0-255,可以使用比 \d+
更复杂的正则表达式,如下所示:
(?:\d{1,2}|1\d{2}|2[0-4]\d|25[0-5])
匹配“任何一位或两位数字,或‘1’后跟任何两位数字,或‘2’后跟‘0’到‘4’中的任何一个,后跟任何数字,或‘25’后跟任何数字‘0’到‘5’”。将 \d
替换为 ,会将完整的字符串修改表达式变为:
const allowedRegexStr = '^(?:' +
allowedIPpatterns.
join('|').
replace(/\./g, '\\.').
replace(/X/g, '(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])') +
')$';
并且使实际的正则表达式看起来更加笨拙:
^(?:10\.(?:\d{1,2}|1\d{2}|2[0-4]\d|25[0-5])\.(?:\d{1,2}|1\d{2}|2[0-4]\d|25[0-5]).(?:\d{1,2}|1\d{2}|2[0-4]\d|25[0-5])|12\.122\....
但你不必看它,只需与它匹配即可。 :)
关于Javascript 多个正则表达式模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10236447/