0

我试图从查看站点中的某些徽标和链接中排除一些内部 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
4

5 回答 5

9

引用句点,将 X 替换为\d+,然后用管道将它们全部连接在一起:

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.XX' 形式的所有 IP”的一个正则表达式是这样的:

^12\.122\.\d+\.\d+$

  • ^表示匹配必须从字符串的开头开始;否则,112.122.XX IP 也会匹配。
  • 12等:数字匹配自己
  • \.: 正则表达式中的句点完全匹配任何字符;我们想要文字句点,所以我们在前面放了一个反斜杠。
  • \d: 的简写[0-9]; 匹配任何数字。
  • +: 表示“1 个或多个” - 在这种情况下,1 个或多个数字。
  • $: 与 类似^,这意味着匹配必须在字符串的末尾结束。

因此,我们将 IP 模式转换为这样的正则表达式。对于单个模式,您可以使用如下代码:

const regexStr = `^` + ipXpattern. 
  replace(/\./g, '\\.').
  replace(/X/g, '\\d+') + 
  `$`;

它只是将所有.s替换为\.and Xs 并将and\d+粘贴在末端。^$

(注意加倍的反斜杠;字符串解析和正则表达式解析都使用反斜杠,所以无论我们想要一个字面量使其通过字符串解析器到达正则表达式解析器,我们都必须将它加倍。)

在正则表达式中,替换 this|that匹配任何匹配this或的内容that。因此,如果我们将列表转换为表单的单个正则表达式,我们可以一次检查所有 IP 的匹配项re1|re2|re3|...|relast

然后我们可以进行一些重构以使正则表达式匹配器的工作更容易;在这种情况下,由于所有正则表达式都将具有^...$,我们可以将这些约束从单个正则表达式中移出并将它们放在整个事物上:^(10\.\d+\.\d+\.\d+|12\.122\.\d+\.\d+|...)$. 括号使 the^不会成为第一个模式的一部分,也$不会成为最后一个模式的一部分。但是由于普通括号捕获以及分组,并且我们不需要捕获任何内容,因此我将它们替换为非分组版本(?:......)

在这种情况下,我们可以在巨型字符串上进行一次全局搜索和替换,而不是在每个模式上单独进行。所以结果就是上面的代码:

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\....

但你不必看它,只需对它进行匹配即可。:)

于 2012-04-19T21:30:13.270 回答
1

你可以在正则表达式中做到这一点,但它不会很漂亮,特别是因为 JavaScript 甚至不支持冗长的正则表达式,这意味着它必须是一个巨大的正则表达式行,没有任何注释。此外,正则表达式不适合匹配数字范围。我怀疑有更好的工具来处理这个问题。

好吧,好的,这里(对于您提供的示例):

var myregexp = /\b(?:74\.23\.211\.92|(?:12\.(?:122|211)|64\.23)\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])|(?:10|64)\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9]))\b/g;

作为一个冗长(“可读”)的正则表达式:

\b                 # start of number
(?:                # Either match...
 74\.23\.211\.92   # an explicit address
|                  # or
 (?:               # an address that starts with
  12\.(?:122|211)  # 12.122 or 12.211
 |                 # or
  64\.23           # 64.23
 )
 \.                # . 
 (?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\.  # followed by 0..255 and a dot
 (?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])    # followed by 0..255
|                  # or
 (?:10|64)         # match 10 or 64
 \.                # . 
 (?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\.  # followed by 0..255 and a dot
 (?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\.  # followed by 0..255 and a dot
 (?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])    # followed by 0..255
)
\b                 # end of number
于 2012-04-19T21:19:54.683 回答
0

我不完全确定您要在这里实现什么(看起来也不是其他人)。

但是,如果是验证,那么这里有一个验证不使用 RegEx 的 IP 地址的解决方案。首先,在点处拆分输入字符串。然后在数字上使用 parseInt,确保它不高于 255。

function ipValidator(ipAddress) {
var ipSegments = ipAddress.split('.');
for(var i=0;i<ipSegments.length;i++)
    {
        if(parseInt(ipSegments[i]) > 255){
            return 'fail';
        }
    }
return 'match';
}

运行以下返回“匹配”:

document.write(ipValidator('10.255.255.125'));

而这将返回“失败”:

document.write(ipValidator('10.255.256.125'));

这是一个带有一些示例的 jsfiddle 中的注释版本,http://jsfiddle.net/VGp2p/2/

于 2012-04-19T22:16:51.167 回答
0

/^(X|\d{1,3})(\.(X|\d{1,3})){3}$/应该这样做。

于 2012-04-19T20:49:02.710 回答
0

如果您实际上不需要匹配“X”字符,则可以使用:

\b(?:\d{1,3}\.){3}\d{1,3}\b

否则我会使用 cebarrett 提供的解决方案。

于 2012-04-19T21:04:24.197 回答