There are times when an Internet Protocol (IP) address needs to be verified/validated. What are examples of valid IP addresses?
有时需要验证/验证Internet协议(IP)地址。 有效IP地址的示例有哪些?
127.0.0.1
127.0.0.1
1.2.3.4
1.2.3.4
192.168.1.100
192.168.1.100
The pattern is that we have 4 integer values (from 0 to 255) separated by periods. Can we use a really simple regular expression (RegExp) like this?
模式是我们有4个由句点分隔的整数值(从0到255)。 我们可以使用这样一个非常简单的正则表达式(RegExp)吗?
var ipRE = new RegExp( '^\d+\.\d+\.\d+\.\d$' );
var ipRE = new RegExp('^ \ d + \。\ d + \。\ d + \。\ d $');
What does this RegExp mean, and how is it supposed to work?
RegExp是什么意思,它应该如何工作?
^ - This symbol matches the beginning of the string.
^ -此符号与字符串的开头匹配。
\d - This meta-character matches a single digit (i.e., 0 to 9).
\ d-此元字符与一位数字匹配(即0到9)。
+ - This symbol says to repeat the preceding pattern or symbol 1 or more times (i.e., 1 or more digits).
+ -此符号表示重复前面的模式或符号1次或多次(即1个或多个数字)。
\. - This sequence is needed to match a period. Since a period has special meaning in a RegExp, we have to precede it with the backslash to indicate that we don't want the special meaning, we really want to match a period.
\。 -需要此序列以匹配周期。 由于一个正则表达式在RegExp中具有特殊含义,因此我们必须在其前面加上反斜杠以表示我们不希望具有特殊含义,因此我们确实想匹配一个周期。
$ - This symbol matches the end of the string.
$ -此符号与字符串的结尾匹配。
So, this RegExp will match a string containing 4 integer values, separated by periods. How can we check it out to see if it satisfies our requirements?
因此,此RegExp将匹配包含4个整数值(由句点分隔)的字符串。 我们如何检查它是否满足我们的要求?
<html>
<head>
<title>IP address validation</title>
<script type='text/javascript'>
function validate( value ) {
var ipRE = new RegExp( '^\d+\.\d+\.\d+\.\d+$' );
alert( ( ipRE.test( value ) ? '' : 'in' ) + 'valid' );
}
</script>
</head>
<body>
Address: <input type='text' onchange='validate(this.value)'>
</body>
</html>
When we try this simple page, and enter the simplest of IP addresses, (i.e., "0.0.0.0"), and press the Tab key to have the validate() function execute, we will probably be surprised to see the alert dialog box say "invalid". What?!? How did we get this simple RegExp wrong? The answer is that we forgot that the escape character (i.e., the backslash) that is used to identify one of the RegExp meta-characters needs to be present when we create the RegExp. Huh?
当我们尝试这个简单的页面,并输入最简单的IP地址(即“ 0.0.0.0”),然后按Tab键以使
Alright, if you have a trivial alert() string containing '\d', what gets displayed? A "d". In order to have the string being passed to the RegExp() constructor contain the text we want, we have to escape the backslash (i.e., '\\d'), for each and every backslash in the expression... (sigh). So, what we really needed to do was to have the RegExp assignment in the code be:
好吧,如果您有一个包含'\ d'的琐碎的
var ipRE = new RegExp( '^\\d+\\.\\d+\\.\\d+\\.\\d
var ipRE = new RegExp('^ \\ d + \\。\\ d + \\。\\ d + \\。\\ d + $');
Does that fix it? Yes, but it's not quite that simple. What happens if we specify an octet value that is too big? What's an octet? It's one of those 4 integer values between periods. Each octet may only have a value from 0..255. So, let's try an obviously invalid address of 999.999.999.999. Unfortunately, the RegExp, as written says that this is valid. Why? Because it allows each octet to be any positive integer. As long as each octet has 1 or more digits, it matches the RegExp pattern as written.
这样可以解决吗? 是的,但这不是那么简单。 如果指定的八位位组值太大,会发生什么? 什么是八位位组? 它是周期之间这4个整数值之一。 每个八位位组只能有一个从0..255开始的值。 因此,让我们尝试一个显然无效的地址
How do we fix that? Let's begin by figuring out how to validate an octet using a RegExp. We know that we have to have at least 1 digit, so this is simply '\d' (in order to make the regular expressions easier to read, we're going to leave out the double backslashes until we absolutely need them).
我们该如何解决? 让我们从弄清楚如何使用RegExp验证八位字节开始。 我们知道我们必须至少有1位数字,因此这只是'\ d'(为了使正则表达式更易于阅读,我们将省略双反斜杠,直到绝对需要它们为止)。
So far, we know that /^\d$/ can be used to validate that we have 1, and only 1 digit. That takes care of the values from 0-9. Do we want to allow a '0' in the tens position (i.e., is '01' ok)? No, so in order to check a valid 2 digit number (i.e., from 0..99), we need a slightly more complex RegExp:
到目前为止,我们知道/ ^ \ d $ /可用于验证我们只有1位数字。 这样可以处理0-9之间的值。 我们是否要在十位允许“ 0”(即“ 01”可以)? 否,因此为了检查有效的2位数字(即从0..99开始),我们需要稍微复杂一点的RegExp:
var TwoDigits = /^[1-9]\d|\d$/:
var TwoDigits = / ^ [1-9] \ d | \ d $ /:
Does this work? Let's test it.
这样行吗? 让我们测试一下。
<html>
<head>
<title>0..99 validation</title>
<script type='text/javascript'>
function validate( value ) {
var TwoDigits = new RegExp( '^[1-9]\\d|\\d$' );
alert( TwoDigits.test( value ) );
}
</script>
</head>
<body>
0..99: <input type='text' onchange='validate(this.value)'>
</body>
</html>
When we put in single digit values the result is true as expected. What is unexpected is the fact that 100 is also "valid". What is going on? Let's try some different values to see what is going on. Additional testing shows that any two digit values from 10..99 followed by anything (e.g., 10x), and anything followed by a single digit (e.g., A0) are also being seen as valid.
当我们输入一位数字值时,结果将如预期的那样为
This means that the or operator (i.e., the '|') is of a lesser precedence. This means that when we thought that the RegExp was being interpreted as this:
这意味着
/^([1-9]\d|\d)$/
/ ^([1-9] \ d | \ d)$ /
(i.e., the start of string followed by either two digits (the first of which can't be a zero), or a single digit, followed by the end of string). It was, in fact, being interpreted as this:
(即,字符串的开头,后跟两个数字(第一个数字不能为零),或者一个数字,后跟字符串的结尾)。 实际上,它被解释为:
/(^[1-9]\d)|(\d$)/
/(^ [1-9] \ d)|(\ d $)/
(i.e., the start of string followed by two digits, or a single digit followed by the end of string) which is a totally different expression, and not what we intended, or wanted. So, in order to fix it, we need to add parentheses, which changes our RegExp definition to:
(即字符串的开头,后跟两个数字, 或者一个数字,后跟字符串的末尾),这是完全不同的表达式,而不是我们想要的或想要的。 因此,为了修复它,我们需要添加括号,这会将我们的RegExp定义更改为:
var TwoDigits = new RegExp( '^([1-9]\\d|\\d)$' );
var TwoDigits = new RegExp('^([1-9] \\ d | \\ d)$');
When we test this, we get the values we expected. So, this RegExp can be used to verify a number from 0..99.
当我们对此进行测试时,我们得到了我们期望的值。 因此,此RegExp可以用于验证0..99中的数字。
Next, we have to figure out how to get the RegExp to allow only values from 100..255. Building on the two digit expression leads us to the following ranges of values to be matched:
接下来,我们必须弄清楚如何获取RegExp以仅允许100..255中的值。 基于两位数的表达式使我们可以匹配以下值的范围:
250..255 = 25[0-5]
250..255 = 25 [0-5]
200..249 = 2[0-4][0-9] or 2[0-4]\d
200..249 = 2 [0-4] [0-9]或2 [0-4] \ d
100..199 = 1[0-9][0-9] or 1\d\d
100..199 = 1 [0-9] [0-9]或1 \ d \ d
10..99 = [1-9][0-9] or [1-9]\d
10..99 = [1-9] [0-9]或[1-9] \ d
0..9 = [0-9] or \d
0..9 = [0-9]或\ d
I don't know about you, but I find switching back and forth between bracketed groups and escaped meta sequences a little hard to read. Additionally, by only using bracket groups, we don't have to worry about, or remember to double the backslashes. Because of that, I prefer this regular expression for these 5 ranges:
我不了解您,但是我发现在括号内的组和转义的元序列之间来回切换有点难以理解。 此外,仅使用括号组,我们就不必担心或记住加倍反斜杠。 因此,对于这5个范围,我更喜欢使用此正则表达式:
var octet = '^(25[0-5]|2[0-4][0-9]|1[0
var octet ='^(25 [0-5] | 2 [0-4] [0-9] | 1 [0 -9] {2} | [1- 9] [0-9] | [0 -9])$';
and we can verify this RegExp using the following page.
我们可以使用以下页面来验证此RegExp。
<html>
<head>
<title> octet </title>
</head>
<body>
<script type='text/javascript'>
var octet = /^(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])$/;
for ( var i = -1; i < 257; i++ ) {
if ( ! octet.test( '' + i ) ) {
document.write( i + '<br>' );
}
}
</script>
</body>
</html>
The output for which shows that -1 and 256 are the only invalid values from -1..256. This is exactly what we want. One thing to note, however, is that by using the parentheses, we are creating a capturing group. While we're creating a regular expression to validate an IP address, it is unlikely that we will want, or need the individual octets matched. So, how do we change this into a non-capturing group? By changing the simple parentheses ^(25[0-5]|2[0-4][0-9]|1[0-
其输出显示-1和256是-1..256中唯一无效的值。 这正是我们想要的。 但是要注意的一件事是,通过使用括号,我们正在创建捕获组。 当我们创建一个正则表达式来验证IP地址时,我们不太可能想要或需要匹配各个八位字节。 那么,如何将其变成一个非捕获组? 通过更改简单括号^(25 [0-5] | 2 [0-4] [0-9] | 1 [0- 9] {2} | [1-9 ] [0-9] | [0- 9])$使用以下语法: (?:...) 。 因此,RegExp变为:
var octet = /^(?:25[0-5]|2[0-4][0-9]|1
var octet = / ^(?: 25 [0-5] | 2 [0-4] [0-9] | 1 [0-9] {2} | [ 1-9] [0-9] | [0-9])$ /;
And the big question that remains is:
剩下的最大问题是:
How do we build a RegExp to recognize an IP address that is composed of 4, dot (period) separated octets?
我们如何构建RegExp来识别由4个点(句点)分隔的八位字节组成的IP地址?
One way is to build it using the existing octet definition:
一种方法是使用现有的八位位组定义来构建它:
var ip = '(?:' + octet + '\\.){3}' + octet;
var ip ='(?:'+八位位组+'\\。){3}'+八位位组;
When put into a complete script looks like:
当放入完整的脚本时,如下所示:
<html>
<head>
<title> octet </title>
<script type='text/javascript'>
var octet = '(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])';
var ip = '(?:' + octet + '\\.){3}' + octet;
var ipRE = new RegExp( '^' + ip + '$' );
function validate( value ) {
alert( ( ipRE.test( value ) ? '' : 'in' ) + 'valid' );
}
</script>
</head>
<body>
IP Address: <input type='text' onchange='validate(this.value)'>
</body>
</html>
This is looking really good. Can we make it just a little more complex by allowing a valid IP address to be surrounded by square brackets (e.g., [127.0.0.1])? Our first inclination might be to use something like this:
这看起来真的很好。 通过允许有效的IP地址用方括号括起来(例如[127.0.0.1]),我们能否使其稍微复杂一点? 我们的第一个倾向可能是使用这样的东西:
var ipRE = new RegExp( '^\[?' + ip + '\]?$' );
var ipRE = new RegExp('^ \ [?'+ ip +'\]?$');
This means that a leading and trailing square bracket are optional. Testing shows that each of the following are all considered valid:
这意味着前和后方括号是可选的。 测试表明以下各项均被视为有效:
0.0.0.0 - valid, which is good. [127.0.0.1] - valid, which is good. 123.1.2.3]- valid, which is bad (No opening bracket).
-有效, 不好 (没有左括号)。
[192.168.1.101- valid, which is also bad (No closing bracket).
-有效,也很糟糕 (无右括号)。
What happened? Well, the surrounding brackets are considered optional. So, zero, or one occurrence of a bracket at either end of the IP address are considered valid by that RegExp. How do we fix this? Well, essentially, we have to say that in order to be valid, we can have an IP address with or without surrounding matching brackets. How do we do this? The most reasonable way is to use something like this:
发生了什么? 好吧,周围的括号被认为是可选的。 因此,该RegExp认为IP地址两端的零个或一个括号出现是有效的。 我们该如何解决? 好吧,从本质上讲,我们必须说,为了有效,我们可以拥有一个带有或不带有括号的IP地址。 我们如何做到这一点? 最合理的方法是使用如下所示的内容:
var quad = '(\\[' + ip + '\\])|(' + ip + ')';
var quad ='(\\ ['+ ip +'\\])|(''ip +')';
This means that the whole thing looks like:
这意味着整个过程看起来像:
<html>
<head>
<title> quad </title>
<script type='text/javascript'>
var octet = '(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])';
var ip = '(?:' + octet + '\\.){3}' + octet;
var quad = '(\\[' + ip + '\\])|(' + ip + ')';
var ipRE = new RegExp( '^' + quad + '$' );
function validate( value ) {
if ( ipRE.test( value ) ) {
alert( '1: "' + RegExp.$1 + '"\n2: "' + RegExp.$2 + '"' );
} else {
alert( 'invalid' );
}
}
</script>
</head>
<body>
IP Address: <input type='text' onchange='validate(this.value)'>
</body>
</html>
This is really, really close, but again has the problem that the match is either put in RegExp.$1, or in RegExp.$2, which means that within our code we have to have an additional check to see which pattern was matched. Can this be fixed?
这是真的,真的非常接近,但同样具有这样的比赛
Sure, one way would be to recognize that we are currently only matching values that start at the beginning of a string, and end at the end of the same string. If we want to be able to match this pattern in the middle of a string, we can't just simply use the input value.
当然,一种方法是认识到我们当前仅匹配从字符串开头开始并在同一字符串结尾处结束的值。 如果我们希望能够在字符串中间匹配此模式,则不能仅使用输入值。
So, what we need to do is to change the existing capturing groups (i.e., the simple open/close parentheses) in the definition of quad, into non-capturing groups like this:
因此,我们需要做的是将
var quad = '(?:\\[' + ip + '\\])|(?:' + ip + ')';
var quad ='(?:\\ ['+ ip +'\\])|(?:'+ ip +')';
and surrounding the quad pattern with a capturing group, like this:
并用捕获组围绕四边形图案,如下所示:
var ipRE = new RegExp( '(' + quad + ')' );
var ipRE = new RegExp('('+ quad +')');
This makes the script look like this:
这使脚本看起来像这样:
<html>
<head>
<title> IP address validation </title>
<script type='text/javascript'>
var octet = '(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])';
var ip = '(?:' + octet + '\\.){3}' + octet;
var quad = '(?:\\[' + ip + '\\])|(?:' + ip + ')';
var ipRE = new RegExp( '(' + quad + ')' );
function validate( value ) {
if ( ipRE.test( value ) ) {
alert( '"' + RegExp.$1 + '"' );
} else {
alert( 'invalid' );
}
}
</script>
</head>
<body>
IP Address: <input type='text' onchange='validate(this.value)'>
</body>
</html>
The only possible potential for confusion seems to be the fact that if you try a value like [127.0.0.1 (note the missing closing bracket), it matches the pattern. Look closely though, the leading opening bracket is not considered part of the IP address. If you add a closing bracket, and try again, you will see that the brackets are considered part of the address if they are both present.
唯一可能出现混淆的可能性似乎是,如果您尝试使用
Hopefully you will find this article interesting, and helpful. I decided to write it after taking a close look at the e-mail address RegExp that was described here.
希望您会发现本文有趣而有用。 在仔细查看了此处描述的电子邮件地址RegExp之后,我决定编写它。