Web前端的知识之旅哟—— BOM与正则表达式

BOM

BOM的全称叫做Browser OjbectModel 浏览器对象模型,它定义了操作浏览器的接口。

BOM对象包括:Window、History、Navigator、Screen和Location。但是由于浏览器厂商的不同,BOM对象的兼容性极低,一般情况下,我们只用其中的一部分功能。

具体请参考w3school中的介绍:

http://www.w3school.com.cn/jsref/index.asp

Navigator

navigator.userAgent是我们经常使用的属性,它可以返回客户端的代理值。用这个我们就可以判断当前用户使用的是pc端还是移动端,是什么浏览器。

Screen

screen.availHeight/availWidth 可以查看除了window任务栏之外的屏幕的高度和宽度。

screen.height/width 返回显示器的屏幕的高度和宽度。不过这个兼容的较少。

screen.deviceXDPI/deviceYDPI返回显示屏幕每英寸的水平/垂直点数,即分辨率。DPI越高,分辨率越高。

History

history.length 可以返回当前窗口查看过的网页记录的数量,即浏览历史的长度。

history.back() 可以让浏览器进入到下一个历史页面。

history.forward()  可以让浏览器返回到上一个历史页面。

history.go() 这个方法有一个参数,当参数是正数的时候,前进到下一个历史页面,当是负数的时候,回退到上一个历史页面。即前两个的综合方法。

Location

location.host 可以返回当前的主机名和当前的URL端口号。比如百度就返回www.baidu.com

location.search 设置或返回从问好开始的URL(查询部分)

location.hash 可以跳转到相应的id的元素的位置,和a标签的锚点功能差不多。可以配合css3的:target一起使用改变元素的样式。

location.reload() 方法可以重新加载当前页面

BOM就介绍这么多,大家可以看看文档学习一下其他的东西。

正则表达式

在开始讲解正则表达式之前,我们先了解一下转义字符“\”。

我们如果想要打印出来双引号,因为双引号本身是一种语法规则,所以正常情况下是打印不出来的,这个时候就需要用到转义字符“/”来把双引号转化成普通的字符而不是语法规则。


1.  
2. var str = ‘\”\”‘;
3. console.log(str); // “”
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

转义字符配合特殊的字母有特殊的意义:

\n 代表字符串和换行

\r 代表字符串的回车

\t 代表制表符tab

等等

多行字符串

1.真正的多行字符串,在每一行最后加一个\n就可以了。

2.为了让结构看起来清晰,我们在编辑器中人为的换行,但是本身并不是多行字符串,这个时候只需要在每一行末尾加一个“\”就可以了。


1.  
2. var str = ‘\
3. <div class=”demo”>\
4. <span></span>\
5. <p></p>\
6. </div>\
7.
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

了解了转义字符之后,下面我们正式进入正则表达式部分。

正则表达式的作用

正则表达式是进行字符串匹配检测的,当我们为了匹配特殊字符或有特殊匹配原则的字符的时候,正则表达式是最佳的选择。

正则表达式(RegExp)有两种创建方式:

1.直接量


1.  
2. var reg = /abc/;
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

2.构造函数


1.  
2. var reg = new RegExp(‘abc’);
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

要匹配的字符串放在第一个参数,或者将一个现成的正则表达式放进第一个参数。


1.  
2. var reg = /abc/;
3. var reg2 = new RegExp(reg);
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

修饰符

一个正则表达式有三个描述的属性g、i、m,表示三种特定的修饰功能。


1.  
2. var reg = /abc/gim;
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

在直接量中直接在后面加上gim就可以了,但是在构造函数中,我们要把修饰符放在第二个参数上。


1.  
2. var reg = new RegExp(‘abc’, ‘gim’);
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

这两种写出来的效果是一模一样的,但是由于构造函数书写起来太麻烦而且还需要转义字符,个人推荐用直接量来构造正则表达式。

正则表达式上面有一个方法test(),可以测试一个字符串符不符合这个匹配规则。


1.  
2. var reg = /abc/g;
3. console.log(reg.test(‘abcabc’)); // true
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

这样就实现了一个最基本的匹配了。

1.i (ignore) 可以忽略大小写。

2.g (global) 全局匹配。


1.  
2. var reg = /abc/;
3. var str = ‘abcabcabc’;
4. console.log(str.match(reg)); // [“abc”, index: 0, input: “abcabcabc”]
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

不写g的时候会返回一个类数组,写上g会返回一个数组,里面有所有的3个abc。


1.  
2. var reg = /abc/g;
3. var str = ‘abcabcabc’;
4. console.log(str.match(reg)); // [“abc”, “abc”, “abc”]
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

3.m (multiline)多行匹配


1.  
2. var reg = /^e/igm;
3. var str = “abc\nebcd”;
4. console.log(str.match(reg));
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

这个reg的作用是匹配以e开头的字符串,如果不加m,这个str是无法匹配的,因为\n也算一个字符,它后面的e不算是开头的字符,但是加上m之后,\n就会被正则表达式看成是正常的换行符,因此后面的e会被看做是下一行的开头的字符,因此就可以匹配出来了。

表达式

1.[abc] 查找方括号之间的任何字符。

匹配的是一位字符,不过是括号里面的任何一位都可以。


1.  
2. var reg = /[abcd]/g;
3. var str = ‘code’;
4. console.log(str.match(reg)); // [“c”, “d”]
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

现在反悔的一个数组,把str中的所有a或者b或者c都返回出来了。

我们还可以写一个范围,比如[a-zA-Z0-9],这样就代表所有的英文字母和数字。


1.  
2. var reg = /[a-zA-Z0-9]/g;
3. var str = ‘code1024’;
4. console.log(str.match(reg)); // [“c”, “o”, “d”, “e”, “1”, “0”, “2”, “4”]
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

这样匹配出来的就是一个code1024

2.[^abc] 查找任何不属于方括号里面的字符

注意这里的“^”是写在方括号里面的,和前面的代表开头的“^”不是一个意思。当这个符号出现在方括号里面的时候,就代表非的意思,除了方括号里面写的,其他的字符都符合。


1.  
2. var reg = /[^a-zA-Z]/g;
3. var str = ‘code1024’;
4. console.log(str.match(reg)); // [“1”, “0”, “2”, “4”]
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

这个表达式的意思就是除了字母之外的其他字符都符合要求。

3.()

括号的作用是提高优先级和产生子表达式的作用。

4.|

或表达式,和[]差不多,可以配合()来使用。


1.  
2. var reg = /a|b/g;
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

这个正则表达式代表ab或者cb都可以。


1.  
2. var reg = /(a|c)b)/g;
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)


1.  
2. var reg =/(blue|red)abc/;
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

如果不加括号的话,就是匹配blue或者redabc,现在加上括号了就是匹配blueabc或者redabc。

元字符

和表达式差不多,元字符是代表区间的。

1.“.”

这个符号可以匹配除了换行符(\n)和行结束符(\r),除了这两个字符之外其他的字符都可以匹配出来。

2.\w

这个元字符代表单词字符的意思,即A-Za-z0-9_

注意这个是可以匹配下划线的。

3.\W

除了\w的单词字符之外的其他字符。

4.\d

代表数字字符,即0-9

5\D

代表除了数字字符之外的其他字符。

6.\s

查找空白字符。

空白字符都包括:空格符、制表符(\t)、回车符(\r),换行符(\n),垂直换行符(\v)、换页符(\f)。

因此\s = [\n\t\r\v\f];

7.\S

查找非空白字符,即除了\s包括的空白字符之外的其他字符。

我们如果要匹配任意字符的话,就可以搭配起来使用了:

[\s\S]、[\d\D]、[\w\W]等都可以

8.\b

匹配单词边界。


1.  
2. var str = ‘accb bdaccd efg’;
3. var reg = /\bacc/;
4. console.log(str.match(reg)); // [“acc”]
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

这样匹配的就是第一个acc,后面的acc前面不是单词边界,因此不符合匹配规则。

9.\B

非单词边界


1.  
2. var str = ‘accb bdaccd efg’;
3. var reg = /\Bacc/;
4. console.log(str.match(reg)); // [“acc”]
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

匹配的就是中间的acc。

注意,一个汉字就是一个单词,每一个汉字的两边都有默认的单词边界。


1.  
2. var str = ‘维生素c’;
3. var reg = /\bc/;
4. console.log(str.match(reg)); // [“c”, index: 3, input: “维生素c”]
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

量词

以下的n代表一个变量,可以是表达式或者元字符。

1.n+

匹配至少一个变量n


1.  
2. var str = ‘bcdaaaaagbaaasaaka’;
3. var reg = /a+/g;
4. console.log(str.match(reg)); // [“aaaaa”, “aaa”, “aa”, “a”]
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

可以把全部的a当做一位来匹配出来。

2.n*

匹配至少零个变量n


1.  
2. var reg = /a*c/g;
3. var str = ‘abc’;
4. console.log(str.match(reg)); // [“c”]
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

这种情况下只有前面是a*0才有可能匹配成功。


1.  
2. var reg = /\w*/g;
3. var str = ‘aabbbccc’;
4. console.log(str.match(reg)); // [“aabbbccc”, “”]
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

最后有一个空串,因为前面的单词被\w匹配出来,最后还有一个空字符可以被\w0匹配出来。

两个字符之间都有一个空字符, ab-> [‘a’, ”, ‘b’];

3.n?

匹配0-1个变量n


1.  
2. var reg=/(aa|b)?/g;
3. var str = ‘aaaaacb’;
4. console.log(str.match(reg)); // [“aa”, “aa”, “”, “”, “b”, “”]
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

中间的空串是因为匹配了空串,?取0的情况。

4.n{x}

可以规定匹配x个变量n


1.  
2. var reg = /a{4}/;
3. var str = ‘aaaaa’;
4. console.log(str.match(reg)); // [“aaaa”, index: 0, input: “aaaaa”]
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

并且大括号可以写一个区间,中间用逗号链接。


1.  
2. var reg = /a{1,4}/g;
3. var str = ‘aaaaa’;
4. console.log(str.match(reg)); // [“aaaa”, “a”]
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

或者第二个范围不写,这样就代表到无穷的范围。


1.  
2. var reg = /a{1,}/g;
3. var str = ‘aaaaa’;
4. console.log(str.match(reg)); // [“aaaaa”]
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

这里默认的是贪婪匹配,即尽可能匹配多个字符。


1.  
2. var reg = /a{1,4}/g;
3. var str = ‘aaaaaa’;
4. console.log(str.match(reg)); // [“aaaa”, “aa”]
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

当我们在后面加一个”?”之后,就会变成最小匹配,尽可能匹配少的字符。


1.  
2. var reg = /a{1,4}?/g;
3. var str = ‘aaaaaa’;
4. console.log(str.match(reg)); // [“a”, “a”, “a”, “a”, “a”, “a”]
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

当然,不只是{}后面可以加”?”,其他的比如*?、+?等等后面都可以加问号。

5.n$

匹配以n结尾的字符


1.  
2. var reg = /ab$/;
3. var str = ‘abab’;
4. console.log(str.match(reg)); // [“ab”, index: 2, input: “abab”]
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

只能找到最后一组ab

6.^n

匹配以n开头的字符,注意不是[]里面的^。


1.  
2. var reg = /^acb/g;
3. var str = ‘acbacb’;
4. console.log(str.match(reg)); // [“acb”]
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

只能匹配出来第一个acb。


1.  
2. var reg = /^ab$/g;;
3. var str = ‘abcabc’;
4. console.log(str.match(reg)); // null
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

这种写法就要求从a开头,挨着的b是结尾的。”abab“现在就匹配不出来了。


1.  
2. var reg = /^abc$/g;;
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

这种写法可以匹配固定字符串abc。

小题目:

写一个正则表达式,检验字符串首尾是否有数字。


1.  
2. var reg = /^\d|\d$/gi;
3. console.log(reg.test(‘12asdfv’)); // true
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

7.n(?=xxx)

正向预查(正向断言)


1.  
2. var reg = /x(?=abc)/g;
3. var str = ‘xabcxbcdaabc’;
4. console.log(str.match(reg)); // x
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

后面是abc的那个n,匹配的是n,后面有abc是一种条件。

如果n是一个空,那么就查找后面是abc的a前面那个空串了。


1.  
2. var reg = /(?=abc)/g;
3. var str = ‘xabcxbcdaabc’;
4. console.log(str.match(reg)); // [“”, “”]
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

8.n(?!xxx)

非正向预查

匹配后面不是abc的n。

• 我们如果要匹配*、?等这些字符的话,就需要在前面加上一个转义字符“/”了。

RegExp对象

属性

1.global multiline ignoreCase

这三个属性可以检测是否有gim修饰。

2.source

代表正则表达式本身,即两个斜线中间的部分。


1.  
2. var reg = /abc\w\d/gim;
3. console.log(reg.source); // abc\w\d
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

方法

1.exec

这个方法可以检测字符串中指定的值,返回知道的值并确定其位置。


1.  
2. var reg = /abc/;
3. var str = “bcabcdabcda”;
4. console.log(reg.exec(str)); // [“abc”, index: 2, input: “bcabcdabcda”]
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

返回的是一个类数组,其中的index是匹配出的字符开始的位置。

不论执行多少次结果都一样。

jQuery源码里面就用了很多exec方法。

我们前面提到()括号除了优先级之外,还可以产生子表达式。


1.  
2. var reg = /(a)(b)(c)/;
3. var str = “bcabcdabcda”;
4. console.log(reg.exec(str)); // [“abc”, “a”, “b”, “c”, index: 2, input: “bcabcdabcda”]
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

返回的类数组会把三个子表达式匹配的内容也写出来。

第一个子表达式的a是第一个abc里面的a,子表达式b是abc里面的b,子表达式c是abc里面的c。

当我们不想让括号匹配出来字符作为子表达式,只充当优先级的作用的时候,那么在()的最前面加上“?:”就可以取消子表达式的作用了。


1.  
2. var reg = /(?:a)(?:b)(c)/;
3. var str = “bcabcdabcda”;
4. console.log(reg.exec(str)); // [“abc”, “c”, index: 2, input: “bcabcdabcda”]
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

这里的”?:”叫做不记录子表达式。

而有了子表达式,我们也有相应的可以选择出子表达式的表达式。

反向引用:

匹配形如1221形式的字符串,比如abba,deed等。我们可以通过子表达式和反向引用就可以实现。


1.  
2. var reg = /(\w)(\w)\2\1/ ;
3. var str = “abba”;
4. console.log(reg.exec(str)); // [“abba”, “a”, “b”, index: 0, input: “abba”]
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

\1代表和第一个子表达式匹配到的相同的内容,第一个\w匹配到什么这里的\1就是什么,\2同理。

以上是我们的正则表达式没有写g全局时候的情况,当我们写上g之后情况又会变得不一样了。


1.  
2. var reg = /abc/g;
3. var str = “bcabcdabcda”;
4. console.log(reg.exec(str)); // [“abc”, index: 2, input: “bcabcdabcda”]
5. console.log(reg.exec(str)); // [“abc”, index: 6, input: “bcabcdabcda”]
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

执行第一次的结果和没有全局时候是一样的,但是从第二次开始就不同了。

第二次index变成了6,匹配的是第二组abc。

所以加上g之后,后面的匹配开始的位置是从上一次匹配结束的位置开始,而不是从头开始。

如果走到最后也没有符合的字符串的话,就会返回null。但是下一再执行会回到开头开始匹配。

这一切不同之处都是因为正则表达式还有一个属性叫做lastIndex,这个属性基本只有全局的时候才有作用。他会记录表达式上一次匹配完了之后的位置,然后让下一次匹配从lastIndex的位置开始。

如果我们中途改变了lastIndex 的数值,那么我们就可以改变下一次匹配开始的位置了。


1.  
2. var reg = /abc/g;
3. var str = “bcabcdabcda”;
4. reg.lastIndex = 4;
5. console.log(reg.exec(str)); // [“abc”, index: 6, input: “bcabcdabcda”]
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

现在第一次执行结果匹配的就是第二个abc。

String上的一些方法

1.search

检索与正则表达式相匹配的位置,匹配成功即结束,与g无关,匹配失败则会返回-1。

2.match

找到一个或多个正则表达式的匹配,当非全局匹配时和exec显示的一样,是一个类数组,但是没有lastIndex,全局匹配时会返回一个数组。

3.split

split是以什么为分隔符把字符串分割成一个数组,这里的分隔符可以写一个正则表达式。


1.  
2. var reg = /[-\d]/g;
3. var str = ‘a-c-d-a0f-e’;
4. console.log(str.split(reg)); // [“a”, “c”, “d”, “a”, “f”, “e”]
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

4.replace

替换与正则表达式匹配的字串。

这个方法非常非常重要,配合正则表达式会变得很灵活。

str.replace()有两个参数,第一个是目标字符串,可以是一个正则表达式,也可以是一个字符串,第二个参数是替换成的字符串。


1.  
2. var str = ‘abcdbcdbcd’;
3. var reg = /ab/g;
4. console.log(str.replace(‘bc’, ‘aa’)); // aaadbcdbcd
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

只改第一个ab,后面的ab不改。

变成aaadbcdbcd。

如果想要全部替换就要写正则表达式。


1.  
2. var str = ‘abcdbcdbcd’;
3. var reg = /(\w)(\w)/g;
4. console.log(str.replace(reg, ‘aa’)); // aaaaaaaaaa
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

现在有一个字符串“ab”,如果我们想要通过正则表达式来调换两个字母的位置,也需要用这个方法。

在第二个参数的位置,字符串里面可以写$、$1、$2…等等,其中$代表匹配出来的字符串,$1代表子表达式1,$2代表子表达式2.。

这样我们通过这种参数就可以实现简单的交换字母了。


1.  
2. var str = ‘ab’;
3. var reg = /(\w)(\w)/g;
4. console.log(str.replace(reg, ‘$2$1’)); // ba
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

当然这只是第一种用法,还有第二种用法,在第二个参数中可以传一个函数,系统会自动调用这个函数,然后替换成这个函数返回的字符串。

var str = ‘ab’;

var reg = /(\w)(\w)/g;

console.log(str.replace(reg, function () {

return ‘abc’

})); // abc

整体被替换成了abc。

函数可以写形参,从前到后分别代表匹配出来的字符串、第一个子表达式、第二个子表达式等等。


1.  
2. var str = ‘ab’;
3. var reg = /(\w)(\w)/g;
4. console.log(str.replace(reg, function ($, $1, $2) {
5. return $2 + $1;
6. })); // ba
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

这个样子同样可以实现交换字母的功能。

正则表达式的大部分知识点就这么多哟~

下面我们来做几个题目练习一下正则表达式的使用吧!

1.将形如aaaabbbb字符串调换成bbbbaaaa形式。


1.  
2. var str = ‘aaaabbbb’;
3. var reg = /(\w{4})(\w{4})/g;
4. str.replace(reg, ‘$2$1’);
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

2.将‘my-fist-name’这样的用‘-’连接字符串变成小驼峰式的写法。


1.  
2. var str = ‘my-first-name’;
3. var reg = /-(\w)/g;
4. str.replace(reg, function ($, $1) {
5. return $1.toUpperCase();
6. })
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

3.将一串连续的数字,变成如下形式:

100000000 —> 100,000,000


1.  
2. var str = ‘100000000’;
3. var reg = /(?=((\B)\d{3})+$)/g;
4. console.log(str.replace(reg, ‘,’));
JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)