十、JavaScript 正则表达式(RegExp 对象)

198 阅读6分钟

正则表达式

JavaScript 字符串是在编程中使用最多的一种数据类型,很多地方都需要对字符串进行操作,例如判断一个字符串是否为一个合法的 E-mail 地址、从字符串截取指定的部分等。

正则表达式是一种用于匹配字符串或特殊字符的一种逻辑公式,所谓逻辑公式就是由一些特定字符组合成的,用来表示某些规则的特殊字符串,可以表达对字符串数据的过滤逻辑。

什么是正则表达式

正则表达式(regular expression)是一种表达文本模式(即字符串结构)的方法,有点像字符串的模板,常常用来按照“给定模式”匹配文本。比如,正则表达式给出一个 Email 地址的模式,然后用它来确定一个字符串是否为 Email 地址。JavaScript 的正则表达式体系是参照 Perl 5 建立的。

image.png

image.png

image.png

符号释义
^表示匹配开头
$表示匹配结尾
\d表示匹配数字

示例1

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        var str = '223344'; // 需要验证的字符串

        var regexp = /^\d{6}$/;  // 正则表达式规则

        if (regexp.test(str)) {
            alert('验证成功');
        } else {
            alert('验证失败');
        }
    </script>
</body>

</html>
image.png

示例2

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        // 以m开头 n结尾 中间是6位数字
        var regexp = /^m\d{6}n$/;

        var str1 = 'm563421n';
        var str2 = 'm56342n';
        var str3 = 'm5634 1n';

        console.log(regexp.test(str1));
        console.log(regexp.test(str2));
        console.log(regexp.test(str3));
    </script>
</body>

</html>
image.png

正则表达式的创建

image.png 新建正则表达式有两种方法。一种是使用字面量,以斜杠表示开始和结束。

var regex = /xyz/;

另一种是使用RegExp构造函数。

var regex = new RegExp('xyz');

上面两种写法是等价的,都新建了一个内容为xyz的正则表达式对象。它们的主要区别是,第一种方法在引擎编译代码时,就会新建正则表达式,第二种方法在运行时新建正则表达式,所以前者的效率较高。而且,前者比较便利和直观,所以实际应用中,基本上都采用字面量定义正则表达式。

RegExp构造函数还可以接受第二个参数,表示修饰符(详细解释见下文)。

var regex = new RegExp('xyz', 'i');
// 等价于
var regex = /xyz/i;

上面代码中,正则表达式/xyz/有一个修饰符i

使用构造函数的形式去创建正则应注意如下 image.png

正则表达式是引用类型值

正则表达式是引用类型值,所以两个正则表达式,是不可能相等的

它们比较的是内存中的地址是否相同

image.png

console.log(typeof regexp); // object

元字符

image.png

image.png 大部分字符在正则表达式中,就是字面的含义,比如/a/匹配a/b/匹配b。如果在正则表达式之中,某个字符只表示它字面的含义(就像前面的ab),那么它们就叫做“字面量字符”(literal characters)。

/dog/.test('old dog') // true

上面代码中正则表达式的dog,就是字面量字符,所以/dog/匹配old dog,因为它就表示dog三个字母连在一起。

除了字面量字符以外,还有一部分字符有特殊含义,不代表字面的意思。它们叫做“元字符”(metacharacters),主要有以下几个。

(1)点字符(.)

点字符(.)匹配除回车(\r)、换行(\n) 、行分隔符(\u2028)和段分隔符(\u2029)以外的所有字符。注意,对于码点大于0xFFFF字符,点字符不能正确匹配,会认为这是两个字符。

/c.t/

上面代码中,c.t匹配ct之间包含任意一个字符的情况,只要这三个字符在同一行,比如catc2tc-t等等,但是不匹配coot

(2)位置字符

位置字符用来提示字符所处的位置,主要有两个字符。

  • ^ 表示字符串的开始位置
  • $ 表示字符串的结束位置
// test必须出现在开始位置
/^test/.test('test123') // true

// test必须出现在结束位置
/test$/.test('new test') // true

// 从开始位置到结束位置只有test
/^test$/.test('test') // true
/^test$/.test('test test') // false

(3)选择符(|

竖线符号(|)在正则表达式中表示“或关系”(OR),即cat|dog表示匹配catdog

/11|22/.test('911') // true

上面代码中,正则表达式指定必须匹配1122

多个选择符可以联合使用。

// 匹配fred、barney、betty之中的一个
/fred|barney|betty/

选择符会包括它前后的多个字符,比如/ab|cd/指的是匹配ab或者cd,而不是指匹配b或者c。如果想修改这个行为,可以使用圆括号。

/a( |\t)b/.test('a\tb') // true

上面代码指的是,ab之间有一个空格或者一个制表符。

选择符( | )解析:

要匹配的字符串是纯数字或纯字母,要如何书写正则表达式呢?

有的小伙伴已经想到了,写两个正则表达不就好了,如下面这种写法:

var str1 = "1111"
var str2 = "imooc"
var str3 = "1111imooc"
var reg1 = /^\d+$/ // 匹配纯数字
var reg2 = /^[a-zA-Z]+$/ //匹配纯字母
 console.log(reg1.test(str1) || reg2.test(str1)) //true
console.log(reg1.test(str2) || reg2.test(str2)) //true
console.log(reg1.test(str3) || reg2.test(str3)) //false

上面代码中,str1是纯数字,符合第一个正则,匹配结果返回true, str2是纯字母,符合第二个正则,匹配结果返回true,st3是数字字母组成的,不符合条件,返回false。

这确实也是一种解决方式,但是四配的时候需要验证两次,才能知道这个字符串是纯数字还是纯字母,有些麻烦,接下来,讲解一种更简单直接的方式,元字符或

定义

正则中使用竖线 | 表示或,表示只匹配指定几项之间的一项

使用方式

对x|y表示匹配x或y,也就是说两种中匹配一个,只要匹配到其中一个,就不会再匹配另外一个了

示例1:

var str = "ab"
var reg = /a|ab/
console.log(reg.exec(str)) // a

上面这段代码中,/a|ab/表示匹配a或ab,从字符串左侧开始匹配,匹配到a时,就不会在匹配ab了,所以返回结果是a。

606293d609a2741315730313.png 示例2:

var str1 = "imoochtmlcccjs"
var str2 = "jsimooccss"
var str3 = "cssimoochtml"
var reg = /html|css|js/
console.log(reg.exec(str1)) // html
console.log(reg.exec(str2)) // js
console.log(reg.exec(str3)) // css

上面这段这段代码中,str1中匹配到html就不会再匹配后面的js 了,所以返回结果是html,同理,匹配str2返回的结果是js,匹配str3返回的结果是css

606293e909ddafaf15730350.png 经过上面的讲解,相信已经了解了元字符或的使用方式,那么我们就可以使用元字符或的方式,解决文章开头提到匹配纯数字或纯字母的问题了,代码如下:

var str1 = "1111"
var str2 = "imooc"
var str3 = "1111imooc"
var reg = /^\d+$|^[a-zA-Z]+$/
console.log(reg.test(str1)) // true
console.log(reg.test(str2)) // true
console.log(reg.test(str3)) // false

上面这段代码中,str1属于纯数字,匹配结果返回true,str2属于纯字母,匹配结果返回true,str3是由数字字母组成的,不符合纯数字或纯字母这个条件,匹配结果返回false

606293f509d318b515700368.png

预定义模式

预定义模式指的是某些常见模式的简写方式。

  • \d 匹配0-9之间的任一数字,相当于[0-9]
  • \D 匹配所有0-9以外的字符,相当于[^0-9]
  • \w 匹配任意的字母、数字和下划线,相当于[A-Za-z0-9_]
  • \W 除所有字母、数字和下划线以外的字符,相当于[^A-Za-z0-9_]
  • \s 匹配空格(包括换行符、制表符、空格符等),相等于[ \t\r\n\v\f]
  • \S 匹配非空格的字符,相当于[^ \t\r\n\v\f]
// \s 的例子
/\s\w*/.exec('hello world') // [" world"]

元字符注意事项

db737704cdbc406493ceaf0f387fae71_tplv-k3u1fbpfcp-watermark.png

元字符使用案例

a8e4516dbf684246a994fcdd4cb91fd9_tplv-k3u1fbpfcp-watermark.png

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        var regexp = /^\d{3}-\d{4}-\d{3}$/;

        var str1 = '123-3456-990';

        console.log(regexp.test(str1));
    </script>
</body>

</html>
image.png
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        var regexp = /^\w{3}-\w{4}-\w{3}$/;

        var str1 = 'abc-aiwe-ert';
        var str2 = 'abc-aiwe-_rt';

        console.log(regexp.test(str1));
        console.log(regexp.test(str2));
    </script>
</body>

</html>
image.png

字符的转义

image.png 本章节中讲过^或#或.它们都有正则中代表的意义,如果说当需要被验证的字符串中本身就带有^或#或.的符号。

那么就可以直接加上一个反斜杠\让^或#或.这些符号代表它们自己本身。而不代表正则表达式中的意义。

正则表达式中那些有特殊含义的元字符,如果要匹配它们本身,就需要在它们前面要加上反斜杠。比如要匹配+,就要写成+

/1+1/.test('1+1')
// false

/1+1/.test('1+1')
// true

上面代码中,第一个正则表达式之所以不匹配,因为加号是元字符,不代表自身。第二个正则表达式使用反斜杠对加号转义,就能匹配成功。

正则表达式中,需要反斜杠转义的,一共有12个字符:^.[$()|*+?{和``。需要特别注意的是,如果使用RegExp方法生成正则对象,转义需要使用两个斜杠,因为字符串内部会先转义一次。

(new RegExp('1+1')).test('1+1')
// false

(new RegExp('1\+1')).test('1+1')
// true

上面代码中,RegExp作为构造函数,参数是一个字符串。但是,在字符串内部,反斜杠也是转义字符,所以它会先被反斜杠转义一次,然后再被正则表达式转义一次,因此需要两个反斜杠转义。

image.png 正常来说#是不需要加反斜杠 \ 的,有经验的人,在任何符号前都可以加反斜杠,确保表达的是本身的意思

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        var regexp = /^\d{3}\.\d{2}\^\d{2}\#\d{2}$/;  // 正常来说#是不需要加反斜杠(\)的,有经验的人,在任何符号前都可以加反斜杠,确保表达的是本身的意思

        var str = '123.45^67#89';

        console.log(regexp.test(str));
    </script>
</body>

</html>
image.png

练习题

单选1

image.png

单选2

image.png

多选

image.png

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        var str = '你好 欢迎来学习';
        var pat = /\s/;     // 不用开头和结尾
        console.log(pat.test(str));  // true
    </script>
</body>

</html>

单选

image.png

注意:

匹配除字母、数字或者下划线以外的字符。等价于[ ^A-Za-z0-9_ ]

^叫元字符,元字符放在不同的位置是有不同的含义,比如说元字符放到“/^****/中”,例如:/^A-Za-z0-9_/ ,等价于开头第一个字符可以是大写字母A到Z,也可以是小写字母a到z,也可以是数字0到9,也可以是下划线。

那么如果^元字符放入到“[^****]”,例如[^A-Za-z0-9_] ,则是代表不可以是大写字母A到Z,也不可以是小写字母a到z,也不可以是数字0到9也,也不可以是下划线。

方括号表示法

方括号的使用

image.png 字符类(class)表示有一系列字符可供选择,只要匹配其中一个就可以了。所有可供选择的字符都放在方括号内,比如[xyz] 表示xyz之中任选一个匹配。

/[abc]/.test('hello world') // false
/[abc]/.test('apple') // true

上面代码中,字符串hello world不包含abc这三个字母中的任一个,所以返回false;字符串apple包含字母a,所以返回true

有两个字符在字符类中有特殊含义。

image.png (1)脱字符(^)

如果方括号内的第一个字符是[^],则表示除了字符类之中的字符,其他字符都可以匹配。比如,[^xyz]表示除了xyz之外都可以匹配。

/[^abc]/.test('bbc news') // true
/[^abc]/.test('bbc') // false

上面代码中,字符串bbc news包含abc以外的其他字符,所以返回true;字符串bbc不包含abc以外的其他字符,所以返回false

如果方括号内没有其他字符,即只有[^],就表示匹配一切字符,其中包括换行符。相比之下,点号作为元字符(.)是不包括换行符的。

var s = 'Please yes\nmake my day!';

s.match(/yes.*day/) // null
s.match(/yes[^]*day/) // [ 'yes\nmake my day']

上面代码中,字符串s含有一个换行符,点号不包括换行符,所以第一个正则表达式匹配失败;第二个正则表达式[^]包含一切字符,所以匹配成功。

注意,脱字符只有在字符类的第一个位置才有特殊含义,否则就是字面含义。

(2)连字符(-)

某些情况下,对于连续序列的字符,连字符(-)用来提供简写形式,表示字符的连续范围。比如,[abc]可以写成[a-c][0123456789]可以写成[0-9],同理[A-Z]表示26个大写字母。

/a-z/.test('b') // false
/[a-z]/.test('b') // true

上面代码中,当连字号(dash)不出现在方括号之中,就不具备简写的作用,只代表字面的含义,所以不匹配字符b。只有当连字号用在方括号之中,才表示连续的字符序列。

以下都是合法的字符类简写形式。

[0-9.,]
[0-9a-fA-F]
[a-zA-Z0-9-]
[1-31]

上面代码中最后一个字符类[1-31],不代表131,只代表13

连字符还可以用来指定 Unicode 字符的范围。

var str = "\u0130\u0131\u0132";
/[\u0128-\uFFFF]/.test(str)
// true

上面代码中,\u0128-\uFFFF表示匹配码点在0128FFFF之间的所有字符。

另外,不要过分使用连字符,设定一个很大的范围,否则很可能选中意料之外的字符。最典型的例子就是[A-z],表面上它是选中从大写的A到小写的z之间52个字母,但是由于在 ASCII 编码之中,大写字母与小写字母之间还有其他字符,结果就会出现意料之外的结果。

/[A-z]/.test('\') // true

上面代码中,由于反斜杠('')的ASCII码在大写字母与小写字母之间,结果会被选中。

练习示例

image.png

题目1

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        var regexp = /^[a-zA-z]{5}$/;

        var str1 = 'aserg';
        var str2 = 'asergq';
        var str3 = 'a_ergq';

        console.log(regexp.test(str1));
        console.log(regexp.test(str2));
        console.log(regexp.test(str3));
    </script>
</body>

</html>
image.png

题目2

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        var regexp = /^[a-z\.]{5}$/;

        var str1 = 'as..g';
        var str2 = 'ase/d';
        var str3 = 'ase u';

        console.log(regexp.test(str1));
        console.log(regexp.test(str2));
        console.log(regexp.test(str3));
    </script>
</body>

</html>
image.png

题目3

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        var regexp = /^[a-z]{3}[a-ln-z]$/;

        var str1 = 'qwen';
        var str2 = 'asdm';

        console.log(regexp.test(str1));
        console.log(regexp.test(str2));
    </script>
</body>

</html>
image.png

编程练习1

image.png

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        var regexp = /^1[3-9]\d{5}$/;

        var str1 = '1343219';
        var str2 = '1243219';

        console.log(regexp.test(str1));
        console.log(regexp.test(str2));
    </script>
</body>

</html>
image.png

编程练习2

image.png

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        var regexp = /^\w{5}[^0]$/;

        var str1 = 'as34__';
        var str2 = 'as34_0';

        console.log(regexp.test(str1));
        console.log(regexp.test(str2));
    </script>
</body>

</html>
image.png

量词

image.png 重复类

模式的精确匹配次数,使用大括号({})表示。{n}表示恰好重复n次,{n,}表示至少重复n次,{n,m}表示重复不少于n次,不多于m次。

/lo{2}k/.test('look') // true
/lo{2,5}k/.test('looook') // true

上面代码中,第一个模式指定o连续出现2次,第二个模式指定o连续出现2次到5次之间。

量词符

量词符用来设定某个模式出现的次数。

  • ? 问号表示某个模式出现0次或1次,等同于{0, 1}
  • * 星号表示某个模式出现0次或多次,等同于{0,}
  • + 加号表示某个模式出现1次或多次,等同于{1,}
// t 出现0次或1次
/t?est/.test('test') // true
/t?est/.test('est') // true

// t 出现1次或多次
/t+est/.test('test') // true
/t+est/.test('ttest') // true
/t+est/.test('est') // false

// t 出现0次或多次
/t*est/.test('test') // true
/t*est/.test('ttest') // true
/t*est/.test('tttest') // true
/t*est/.test('est') // true

使用示例

image.png 题目1

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        var regexp = /^1\d{10}$/;

        var str1 = '13355557777';
        var str2 = '23355557777';

        console.log(regexp.test(str1));
        console.log(regexp.test(str2));
    </script>
</body>

</html>
image.png

题目2

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        var regexp = /^[a-zA-Z]\d+[a-zA-Z]$/;

        var str1 = 'a1d';
        var str2 = 'aed';

        console.log(regexp.test(str1));
        console.log(regexp.test(str2));
    </script>
</body>

</html>
image.png

题目3

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        var regexp = /^w{3}\.\w{1,}(\.com)|(\.com\.cn)$/;

        var str1 = 'www.adf.com.cn';
        var str2 = 'www.adf.com';

        console.log(regexp.test(str1));
        console.log(regexp.test(str2));
    </script>
</body>

</html>
image.png

修饰符(flags)

image.png

image.png

image.png

修饰符(modifier)表示模式的附加规则,放在正则模式的最尾部。

修饰符可以单个使用,也可以多个一起使用。

// 单个修饰符
var regex = /test/i;

// 多个修饰符
var regex = /test/ig;

(1)g 修饰符

默认情况下,第一次匹配成功后,正则对象就停止向下匹配了。g修饰符表示全局匹配(global),加上它以后,正则对象将匹配全部符合条件的结果,主要用于搜索和替换。

var regex = /b/;
var str = 'abba';

regex.test(str); // true
regex.test(str); // true
regex.test(str); // true

上面代码中,正则模式不含g修饰符,每次都是从字符串头部开始匹配。所以,连续做了三次匹配,都返回true

var regex = /b/g;
var str = 'abba';

regex.test(str); // true
regex.test(str); // true
regex.test(str); // false

上面代码中,正则模式含有g修饰符,每次都是从上一次匹配成功处,开始向后匹配。因为字符串abba只有两个b,所以前两次匹配结果为true,第三次匹配结果为false

(2)i 修饰符

默认情况下,正则对象区分字母的大小写,加上i修饰符以后表示忽略大小写(ignoreCase)。

/abc/.test('ABC') // false
/abc/i.test('ABC') // true

上面代码表示,加了i修饰符以后,不考虑大小写,所以模式abc匹配字符串ABC

(3)m 修饰符

m修饰符表示多行模式(multiline),会修改^$的行为。默认情况下(即不加m修饰符时),^$匹配字符串的开始处和结尾处,加上m修饰符以后,^$还会匹配行首和行尾,即^$会识别换行符(\n)。

/world$/.test('hello world\n') // false
/world$/m.test('hello world\n') // true

上面的代码中,字符串结尾处有一个换行符。如果不加m修饰符,匹配不成功,因为字符串的结尾不是world;加上以后,$可以匹配行尾。

/^b/m.test('a\nb') // true

上面代码要求匹配行首的b,如果不加m修饰符,就相当于b只能处在字符串的开始处。加上m修饰符以后,换行符\n也会被认为是一行的开始。

正则表达式的相关方法

image.png

test()方法

image.png

RegExp.prototype.test()

正则实例对象的test方法返回一个布尔值,表示当前模式是否能匹配参数字符串。

/cat/.test('cats and dogs') // true

上面代码验证参数字符串之中是否包含cat,结果返回true

如果正则表达式带有g修饰符,则每一次test方法都从上一次结束的位置开始向后匹配。

exec()方法

exec() 方法在一个指定字符串中执行一个搜索匹配。返回一个结果数组或 null

image.png

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        var str = '123fds456jkt789';

        var regexp = /\d+/;     // 注意这里不需要指定开头和结尾

        console.log(regexp.exec(str));
    </script>
</body>

</html>

image.png

exec()方法逐条遍历 image.png

image.png 我们在使用exec()的时候往往都会加g修饰符的,如果不加,它只能找到最开头的一个

image.png

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        var str = '123abc456def789';

        var regexp = /\d+/g;     // +表示贪婪的,尽可能多的匹配

        var result = 0;

        while (result = regexp.exec(str)) {
            console.log(result);
        }
    </script>
</body>

</html>

注意 返回的是数组

image.png 解析

while(当检测结果存在的时候,它就会一直检测下去)

循环里面是一条赋值语句,赋值语句也是有返回值的,它的返回值就是等号右边的值

它一边在把等式右边的值赋给左边,一边在检测右面的值是否为真(true),不能为null。数组就是真,null为假;

我们也可以在这里输出索引为0的第一项,方便对查找的结果进行操作:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        var str = '123abc456def789';

        var regexp = /\d+/g;     

        var result = 0;

        while (result = regexp.exec(str)) {
            console.log(result[0]);  // 我们也可以在这里输出索引为0的第一项,方便对查找的结果进行操作
        }
    </script>
</body>

</html>
image.png

练习题

练习1

image.png
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        var str = 'regular expression = regexp';

        var regexp1 = /lar\sexp/;
        var regexp2 = new RegExp('lar\\sexp');

        document.write(regexp1.test(str) + '/');
        document.write(regexp2.test(str) + '/');
        document.write(regexp1.exec(str) + '/');
        document.write(regexp2.exec(str) + '/');
    </script>
</body>

</html>
image.png

练习2

image.png
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        var str = '一个"普通字符"在匹配字符串的时候,匹配与它相同的一个字符';

        var regexp1 = /\"普通字符\"/;
        var regexp2 = new RegExp('\"普通字符\"');

        document.write(regexp1.test(str) + '/');
        document.write(regexp2.test(str) + '/');
        document.write(regexp1.exec(str) + '/');
        document.write(regexp2.exec(str) + '/');
    </script>
</body>

</html>
image.png

练习3

image.png
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        var str = 'JavaScript_RegExp_5@gmail.com';

        var regexp1 = /\_RegExp\_5\@gm/;
        var regexp2 = new RegExp('\\_RegExp\\_5\\@gm');

        var regexp3 = /\_RegExp\_5\@gm/i;
        var regexp4 = new RegExp('\\_RegExp\\_5\\@gm', 'i');

        document.write(regexp1.test(str) + '/');
        document.write(regexp2.test(str) + '/');
        document.write(regexp3.test(str) + '/');
        document.write(regexp4.test(str) + '/');

        document.write(regexp1.exec(str) + '/');
        document.write(regexp2.exec(str) + '/');
        document.write(regexp3.exec(str) + '/');
        document.write(regexp4.exec(str) + '/');
    </script>
</body>

</html>

image.png

字符串的相关正则方法

image.png

search()方法

String.prototype.search()

字符串对象的search方法,返回第一个满足条件的匹配结果在整个字符串中的位置。如果没有任何匹配,则返回-1

'_x_x'.search(/x/)
// 1

上面代码中,第一个匹配结果出现在字符串的1号位置。

  1. 全局匹配在search中没用。

  2. search方法找到匹配的内容后,返回的是被匹配的字符第一位的下标值,没找到返回-1。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        var str = '123saf567jig';

        var regexp1 = /\d/g;   // 全局匹配在search中没用
        var regexp2 = /e/;

        console.log(str.search(regexp1));
        console.log(str.search(regexp2));
    </script>
</body>

</html>
image.png

注意

  • search()方法可以通过正则来进行查找,而indexOf()不行

  • 是字符串调用的search方法

match()方法

使用频率较高

String.prototype.match()

字符串实例对象的match方法对字符串进行正则匹配,返回匹配结果。

var s = '_x_x';
var r1 = /x/;
var r2 = /y/;

s.match(r1) // ["x"]
s.match(r2) // null

从上面代码可以看到,字符串的match方法与正则对象的exec方法非常类似:匹配成功返回一个数组,匹配失败返回null

如果正则表达式带有g修饰符,则该方法与正则对象的exec方法行为不同,会一次性返回所有匹配成功的结果。

var s = 'abba';
var r = /a/g;

s.match(r) // ["a", "a"]
r.exec(s) // ["a"]
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        var str = '123asd789jid000';

        var regexp1 = /\d+/g;    // 注意这里都是全局搜素
        var regexp2 = /\d/g;

        console.log(str.match(regexp1));
        console.log(str.match(regexp2));
    </script>
</body>

</html>

image.png

replace()方法

String.prototype.replace()

字符串对象的replace方法可以替换匹配的值。它接受两个参数,第一个是正则表达式,表示搜索模式,第二个是替换的内容。

str.replace(search, replacement)

正则表达式如果不加g修饰符,就替换第一个匹配成功的值,否则替换所有匹配成功的值。

'aaa'.replace('a', 'b') // "baa"
'aaa'.replace(/a/, 'b') // "baa"
'aaa'.replace(/a/g, 'b') // "bbb"

上面代码中,最后一个正则表达式使用了g修饰符,导致所有的a都被替换掉了。

replace方法的一个应用,就是消除字符串首尾两端的空格。

var str = '  #id div.class  ';

str.replace(/^\s+|\s+$/g, '')
// "#id div.class"

再看如下demo

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        var str = '123jsli456uibu345';

        console.log(str.replace(/[a-z]/g, '*'));    // 将字符串中的小写字母都替换为星号
    </script>
</body>

</html>
image.png
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        var str = '123jsli456uibu345';

        console.log(str.replace(/[a-z]+/g, '*'));    // 将字符串中的小写字母都替换为星号, +号表示尽可能多的匹配
    </script>
</body>

</html>
image.png

split()方法

String.prototype.split()

字符串对象的split方法按照正则规则分割字符串,返回一个由分割后的各个部分组成的数组。

str.split(separator, [limit])

该方法接受两个参数,第一个参数是正则表达式,表示分隔规则,第二个参数是返回数组的最大成员数。

// 非正则分隔
'a,  b,c, d'.split(',')
// [ 'a', '  b', 'c', ' d' ]

// 正则分隔,去除多余的空格
'a,  b,c, d'.split(/, */)
// [ 'a', 'b', 'c', 'd' ]

// 指定返回数组的最大成员
'a,  b,c, d'.split(/, */, 2)
[ 'a', 'b' ]

上面代码使用正则表达式,去除了子字符串的逗号后面的空格。

// 例一
'aaa*a*'.split(/a*/)
// [ '', '*', '*' ]

// 例二
'aaa**a*'.split(/a*/)
// ["", "*", "*", "*"]

上面代码的分割规则是0次或多次的a,由于正则默认是贪婪匹配,所以例一的第一个分隔符是aaa,第二个分割符是a,将字符串分成三个部分,包含开始处的空字符串。例二的第一个分隔符是aaa,第二个分隔符是0个a(即空字符),第三个分隔符是a,所以将字符串分成四个部分。

如果正则表达式带有括号,则括号匹配的部分也会作为数组成员返回。

'aaa*a*'.split(/(a*)/)
// [ '', 'aaa', '*', 'a', '*' ]

上面代码的正则表达式使用了括号,第一个组匹配是aaa,第二个组匹配是a,它们都作为数组成员返回。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        var str = '123lsdf999ueroit789';

        console.log(str.split(/\d+/g));
    </script>
</body>

</html>
image.png

练习题

单选1

image.png

单选2

image.png

练习1

image.png
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        var str = '110报警120急救119火警114查询';
        
        document.write(str.match(/\d+/g));
    </script>
</body>

</html>
image.png

练习2

image.png
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        var str = "2020.02.02";
        
        console.log(str.replace(/\.+/g, '-'));
    </script>
</body>

</html>
image.png

正则表达式的应用

image.png

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        p>span {
            color: red;
            font-size: 14px;
            display: none;
        }
    </style>
</head>

<body>
    <p>
        姓名:
        <input class="nameFiled" type="text">
        <span id="nameWarning">姓名不合法</span>
    </p>
    <p>
        电话:
        <input class="telField" type="text">
        <span id="telWarning">电话不合法</span>
    </p>
    <p>
        Email:
        <input class="eField" type="email">
        <span id="eWarning">Email不合法</span>
    </p>

    <script>
        // 正则验证
        var NameReg = /^[\u4e00-\u9fa5]{2,4}$/;
        var TelReg = /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/;
        var EmailReg = /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/

        // 输入框节点
        var nameFiled = document.getElementsByClassName('nameFiled')[0];
        var telField = document.getElementsByClassName('telField')[0];
        var eField = document.getElementsByClassName('eField')[0];

        // 警示文字节点
        var nameWarning = document.getElementById('nameWarning');
        var telWarning = document.getElementById('telWarning');
        var eWarning = document.getElementById('eWarning');

        // 事件触发
        nameFiled.addEventListener('blur', function () {
            if (NameReg.test(nameFiled.value)) {
                nameWarning.style.display = 'none';
            } else {
                nameWarning.style.display = 'inline';
            }
        }, false);

        telField.addEventListener('blur', function () {
            if (TelReg.test(telField.value)) {
                telWarning.style.display = 'none';
            } else {
                telWarning.style.display = 'inline';
            }
        }, false);

        eField.addEventListener('blur', function () {
            if (EmailReg.test(eField.value)) {
                eWarning.style.display = 'none';
            } else {
                eWarning.style.display = 'inline';
            }
        }, false);
    </script>
</body>

</html>

动画.gif

注册功能

image.png

任务描述

1、用户名输入框,正确的条件是:6-30位字母、数字或_, 以字母开头。
(1) 如果输入内容的不满足条件时,输入框后面的提示内容为。6-30位字母、数字或’_’,字母开头,且字体颜色变为红色。
(2) 如果输入的满足条件,输入框后面的提示内容为:“用户名输入正确”,且字体颜色变成绿色。
2、密码输入框,正确的条件是:6-20位字母或数字组成
(1) 如果输入内容的不满足条件时,输入框下面给出提示内容为:6-20位字母或数字,且字体颜色变为红色。
(2) 如果输入的密码内容是纯数字、纯小写字母或者纯大写字母,密码强度为低,只有第一块变为红色。
(3) 如果是两种类型的结合,那么密码强度为一般,第二块变为橘色。
(4) 如果是三种类型的结合,那么密码强度为高,第三块变为绿色。
3、密码确认框,正确的条件是:与上面的密码输入框的内容一致。
(1) 如果为空,那么后面给出文字提示“输入框不能为空”,且字体颜色变为红色。
(2) 如果输入的密码跟上面的密码不一致,则提示“两次密码输入不一致,请重新输入”且字体颜色变为红色。
(3) 如果输入的密码跟上面一致,则提示“两次输入一致”。
4、满足所有的验证条件,点击下一步提示“信息填写正确”,否则提示“请填写正确的信息”

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        p span.star {
            color: orange;
        }

        input.submit {
            width: 120px;
            height: 40px;
            margin-left: 50px;
            background-color: #FFA500;
            border-radius: 5px;
            color: aliceblue;
        }

        input.submit:hover {
            background-color: #FA7402;
        }

        p .user_warning,
        p .password_warning_one,
        p .password_warning_two,
        p .password_warning_three {
            color: red;
            display: none;
        }

        p span.user_correct {
            color: #1BBB76;
            display: none;
        }

        p span.password_correct {
            color: #1BBB76;
            display: none;
        }

        p span.tip_wrap {
            line-height: 23px;
            display: none;
        }

        p span.tip_wrap .tips {
            width: 30px;
            height: 8px;
            display: inline-block;
        }

        span.tip_wrap .tip_one {
            background-color: red;
        }

        span.tip_wrap .tip_two {
            background-color: orange;
        }

        span.tip_wrap .tip_three {
            background-color: green;
        }
    </style>
</head>

<body>
    <p>
        <span class="star">*</span><span>用 户 名 :</span>
        <input class="input_field" type="text" placeholder="用户设置成功后不可修改">
        <span class="user_warning">6-30位字母、数字或“_”,字母开头</span>
        <span class="user_correct">用户名输入正确</span>
    </p>
    <p>
        <span class="star">*</span><span>登录密码:</span>
        <input class="password_field_one" type="password" placeholder="6-20位字母或数字">
        <span class="password_warning_one">6-20位字母或数字</span>
        <span class="tip_wrap">
            <span class="tips tip_one"></span>
            <span class="tips tip_two"></span>
            <span class="tips tip_three"></span>
        </span>
    </p>
    <p>
        <span class="star">*</span><span>确认密码:</span>
        <input class="password_field_two" type="password" placeholder="请再次输入您的登录密码">
        <span class="password_warning_two">输入框不能为空</span>
        <span class="password_warning_three">两次密码输入不一致,请重新输入</span>
        <span class="password_correct">信息填写正确</span>
    </p>

    <input class="submit" type="submit"></input>

    <script>
        // 节点获取
        var inputField = document.getElementsByClassName('input_field')[0];
        var passwordFieldOne = document.getElementsByClassName('password_field_one')[0];
        var passwordFieldTwo = document.getElementsByClassName('password_field_two')[0];
        var userCorrect = document.querySelector('p span.user_correct');
        var userWarning = document.querySelector('p .user_warning');
        var passwordWarningOne = document.querySelector('p .password_warning_one');
        var passwordWarningTwo = document.querySelector('p .password_warning_two');
        var passwordWarningThree = document.querySelector('p .password_warning_three');
        var passwordCorrect = document.querySelector('p span.password_correct');
        var tipWrap = document.querySelector('p span.tip_wrap');
        var tipOne = document.querySelector('span.tip_wrap .tip_one');
        var tipTwo = document.querySelector('span.tip_wrap .tip_two');
        var tipThree = document.querySelector('span.tip_wrap .tip_three');
        var submitBtn = document.querySelector('input.submit');

        // 正则验证
        var inputRegexp = /^[a-zA-Z]\w{5,29}$/;     // 用户名验证
        var passwordCorrectRegexp = /[a-zA-Z\d]{6,20}/;
        var passwordGradeOne = /(^\d+$)|(^[a-z]+$)|(^[A-Z]+$)/;
        var passwordGradeTwo = /(^[a-zA-Z]+$)|(^[a-z\d]+$)|(^[A-Z\d]+$)/;
        var passwordGradeThree = /^[a-zA-Z\d]+$/;

        // 提交按钮最终判断
        var userBool = false;
        var pwdBoolOne = false;
        var pwdBoolTwo = false;

        // 用户名输入判断
        inputField.addEventListener('blur', function () {
            if (inputRegexp.test(inputField.value)) {
                userCorrect.style.display = 'inline';
                userWarning.style.display = 'none';
                userBool = true;
            } else {
                userWarning.style.display = 'inline';
                userCorrect.style.display = 'none';
            }
        }, false);

        // 第一次密码输入判断
        passwordFieldOne.addEventListener('input', function () {
            if (passwordCorrectRegexp.test(passwordFieldOne.value)) {
                passwordWarningOne.style.display = 'none';
                tipWrap.style.display = 'inline-block';
                pwdBoolOne = true;
                if (passwordGradeOne.test(passwordFieldOne.value)) {
                    tipOne.style.backgroundColor = 'red';
                    tipTwo.style.backgroundColor = 'gray';
                    tipThree.style.backgroundColor = 'gray';
                } else if (passwordGradeTwo.test(passwordFieldOne.value)) {
                    tipOne.style.backgroundColor = 'red';
                    tipTwo.style.backgroundColor = 'orange';
                    tipThree.style.backgroundColor = 'gray';
                } else if (passwordGradeThree.test(passwordFieldOne.value)) {
                    tipOne.style.backgroundColor = 'red';
                    tipTwo.style.backgroundColor = 'orange';
                    tipThree.style.backgroundColor = 'green';
                }
            } else {
                passwordWarningOne.style.display = 'inline';
            }
        }, false);

        // 密码确认判断
        passwordFieldTwo.addEventListener('blur', function () {
            if (passwordFieldTwo.value == '') {
                passwordWarningTwo.style.display = 'inline';
                passwordCorrect.style.display = 'none';
                passwordWarningThree.style.display = 'none';
            } else if (passwordFieldTwo.value == passwordFieldOne.value) {
                passwordCorrect.style.display = 'inline';
                passwordWarningTwo.style.display = 'none';
                passwordWarningThree.style.display = 'none';
                pwdBoolTwo = true;
            } else if (passwordFieldTwo.value != passwordFieldOne.value) {
                passwordWarningThree.style.display = 'inline';
                passwordCorrect.style.display = 'none';
                passwordWarningTwo.style.display = 'none';
            }
        }, false);

        // 提交
        submitBtn.addEventListener('click', function () {
            if (userBool && pwdBoolOne && pwdBoolTwo) {
                alert('信息填写正确');
            } else {
                alert('请填写正确的信息!');
            }
        }, false);
    </script>
</body>

</html>

动画.gif image.png

昨日之深渊,今日之浅谈。路虽远行则将至;事虽难做则可成