正则表达式

test方法

定义

正则表达式描述了一种字符串匹配模式(从左向右进行匹配),通常被用来检索、替换那些符合某个模式(规则)的文本。

声明
  • [1]使用字面量的方式声明正则表达式
      var reg1 = /pattern/flags  
    
  • [2]使用构造函数RegExp声明正则表达式
      new RegExp(pattern,[flags])
    
    • pattern: 正则表达式文本
    • flags:要添加的标志的字符串,可包含下列任何字符的组合
      • g:全局匹配

        找到所有的匹配,而不是在第一个匹配之后停止

      • i:忽略大小写

        在匹配过程中忽略大小写,如果u标志也被启用,使用 Unicode 大小写折叠

      • m : 多行匹配

        将开始和结束字符 (^ and $) 视为在多行上工作。换句话说,匹配每一行的开头或结尾each line (由\n或者\r 分隔),而不仅仅是整个输入字符串的开头或结尾

      • s:点号匹配所有字符

        允许. 去匹配新的行

      • u: unicode

正则匹配
精准匹配

精准匹配是指 仅能匹配一种字符串,如下

  const reg = /hello/
  reg.test('hello q11111') // true

/hello/ 这个正则表达式仅能匹配 hello这一个字符串

其实精准匹配在开发过程中使用频率不高,因为使用字符串的方法能达到一样的效果

 'hello q1111'.includes('hello') // true
模糊匹配

正则表达式的强大之处在于模糊匹配,同一个正则表达式可以匹配多种不同的字符串,完美实现我们想要的效果~

量词

量词{m,n}表示匹配前一个表达式最少连续出现m次,最多出现n次;

  const reg = /hel{1,2}o/
  reg.test('heo') // false
  reg.test('helo') // true
  reg.test('hello') //true
  reg.test('helllo') //false

/hel{1,2}o/表示匹配的第一个字符是h, 第二个字符是e,第三到四个字符是l,最后一个字符是o。

除此之外,还有一些量词的简写形式

  • {m,} 匹配前一个字符至少m次。

  • {m} 等价于{m,m},匹配前一个字符m次。

  • ? 等价于{0,1},匹配前面一个表达式 0 次或者 1 次

  • + 等价于{1,},匹配前一个字符至少1次

  • * 等价于{0,},匹配前一个字符任意次

但是此时存在一个问题,/ab{1,10}/ 表示可连续匹配字符b 1到10次,那如下的匹配结果是什么的? 是ab呢还是abbbbb呢?

'abbbbbc'.match(/ab{1,10}/) // ‘abbbbb’

答案是‘abbbbb’,原因是因为正则表达式默认匹配为贪婪匹配!

所谓贪婪匹配尽可能多的匹配,在符合条件的情况下匹配最多的字符,那么相对应的还有惰性匹配尽可能少的匹配。正则默认情况下是贪婪匹配,若是想要修改为惰性匹配,需要在量词后面加一个问号。

量词后面的问号表示 惰性匹配表示够了吗?够了就不要继续向下匹配了。

'abbbbbc'.match(/ab{1,10}?/) // ‘ab’

那下面的匹配结果是什么呢?

'abbbbbc'.match(/ab{1,10}?c/) 

结果是abbbbbc,这是因为一只要匹配到c才结束,总不能略过中间的b直接到c😂

字符组

字符组使用[]包裹,表示仅需匹配字符组中的某一个字符即可。

const reg = /[helo]/
reg.test('h') // true
reg.test('e') // true
reg.test('s') // false

/[hello]/表示匹配字符为 h、e、l、o中的任意字符,类似于或的关系。

若是字符组中的字符特别多的话,可以使用范围表示法

const reg = /[0-9]/ // 表示匹配字符为所有数字
const reg = /[a-z]/ // 表示匹配字符为所有小写字母
const reg = /[A-Z]/ // 表示匹配字符为所有大写字母

小提示:若是我们仅需匹配字符2,-,5

const reg = /[2-5]/
reg.test('-') // false
reg.test('4') // true

因为在如上正则中 “-”被用作特殊字符,若是仅仅想表示字符原本的含义,需要转义

const reg = /[2\-5]/
reg.test('-') // true
reg.test('4') // false

若是我们需要排除某些字符匹配,如除了 h、e、l、o之外的字符全部都可以匹配,就需要使用排除字符组,在字符组中^表示取返的意思,如下

const reg = /[^abc]/ // 表示除了字符a、b 、c外的其余字符均可匹配
const reg = /[^]/ // 表示可匹配所有字符

除此以外,还有一些量词的简写形式

  • \d就是[0-9]。表示是一位数字。记忆方式:其英文是digit(数字)。

  • \D就是[^0-9]。表示除数字外的任意字符。

  • \w就是[0-9a-zA-Z_]。表示数字、大小写字母和下划线。记忆方式:w是word的简写,也称单词字符。

  • \W是[^0-9a-zA-Z_]。非单词字符。

  • \s是[ \t\v\n\r\f]。表示空白符,包括空格、水平制表符、垂直制表符、换行符、回车符、换页符。记忆方式:s是space character的首字母。

  • \S是[^ \t\v\n\r\f]。 非空白符。

  • .就是[^\n\r\u2028\u2029]。通配符,表示几乎任意字符。换行符、回车符、行分隔符和段分隔符除外。记忆方式:想想省略号…中的每个点,都可以理解成占位符,表示任何类似的东西。

分支结构体系

虽然正则的量词匹配是贪婪的,但是分支匹配却是惰性的~

通过|可以实现组合匹配

'helloword'.match( /hello | helloword/) // null 

/hello | helloword/要匹配的是"hello "或者“ helloword”

 'helloword'.match( /hello|helloword/) // hello 

/hello|helloword/要匹配的是’hello’或者‘helloword’,但是分支结构匹配是惰性的,只要匹配到hello找到符合条件的字符串就不会继续向下匹配了

 'helloword'.match( /helloword|hello/) // helloword 
位置

位置是相邻字符之间的位置。比如,下图中箭头所指的地方:
在这里插入图片描述
单词边界的本质是一个空字符串,其实就是字符中间的位置~
举例说明

hello =  '单词边界' + h + '单词边界' + e + '单词边界' + l + '单词边界' + l + '单词边界' + o + '单词边界'

hello = '' + h + '' + e + '' + l + '' + l + '' + o + ''

在正则中除了 字符匹配,还有一些位置匹配,如下1:

  • ^: 表示匹配字符串的开头,在多行匹配中匹配行开头;

  • $: 表示匹配字符串的结尾,在多行匹配中匹配行结尾;

  • \b: 表示匹配字符串 中每个单词的边界;

    那么在正则中什么情况下会被认为是单词边界呢?

    首先确定在正则中单词由什么组成的? 在正则中单词包含字母数字下划线
    因此在字符串中只要是遇到 非字母数字下划线的字符就会被认为存在一个单词边界!

    举例说明
    "[JS] Lesson_01.mp4"中单词边界分别为 [与J、 S与] 、空格与L、 1与.、 .与m、4与空格6个单词边界;
    单词边界的本质是一个空字符串,其实就是字符中间的位置~

      "[JS] Lesson_01.mp4".match(/\b/g) // ['', '','','','','']
      "[JS] Lesson_01.mp4".replace(/\b/g, '#')// '[#JS#] #Lesson_01#.#mp4#'
    
  • \B为非单词边界:位置仅有单词边界和非单词边界,去掉单词边界其余均为非单词边界
  • ?=p:其中p是一个子模式,即p前面的位置。
      "hello".replace(/(?=l)/g, '#');  // he#l#lo
    
  • ?!p:而(?!p)就是(?=p)的反面意思
     "hello".replace(/(?!l)/g, '#');  // '#h#ell#o#'
    

错误理解: 以^为例

'#12346 #dffscfd #edersfs defa #df'.match(/#[0-9a-z]{2,5}/g)

上述正则表达式/#[0-9a-z]{2,5}/g是什么意思?

因为在我最初的理解中,这个正则要表达的意思是匹配以#开头后面跟随2-5个数字/小写字母的意思,相当于匹配结果为[‘#12346’, ‘#dffsc’, ‘#eders’, ‘#df’]; 但是实际结果并不是因为位置字符并不是相对于匹配结果而言,而是相对于 字符串的位置而言,^表示的是在匹配字符串的开头,因此匹配结果为[‘#12346’]

而且我们可以将固定位置替换为某指定字符(串),如下

 'helloword'.replace(/^/, '开头') // '开头helloword'

在正则中除了 字符匹配,还有一些位置匹配,如下2:

  • `\B: ;
案例

1.匹配16进制的颜色
首先看一下16进制的颜色有什么特点

#FEE8D1 #FFDF9D #fff #fc423e ...

16进制的颜色 以#号开头 可以是3位可以是6位,都为数组、字母(字母最大为f),因此正则可以写为 /#[0-9a-fA-f]{6}|#[0-9a-fa-f]{3}/g

' #FEE8D1 #FFDF9D #fff #fc423e '.match(/#[0-9a-zA-Z]{6}|#[0-9a-zA-Z]{3}/g) // ['#FEE8D1', '#FFDF9D', '#fff', '#fc423e']

错误示范:

' #FEE8D1 #FFDF9D #fff #fc423e '.match(/^#[0-9a-zA-Z]{6}|^#[0-9a-zA-Z]{3}/g) // null
常用方法
[1]exec方法

(1)定义&作用
exec方法是RegExp构造函数原型链上的方法,它的作用是 在字符串中查找匹配的;
(2)返回值分为两种情况

  • 存在(匹配的到):返回值为一个数组,里面包含 匹配字符的值、索引等
  • 不存在(没有匹配到):返回值为null
  • 注:即使为全局匹配,返回的也仅仅是第一个匹配到的数据
    (3)语法
  reg.exec(str)
  // reg是声明的正则表达式
  // str是要进行查询的字符串

(4)实例

  var res = reg2.exec('abbbbbcfhjkjhgabc')
  console.log('res', res) // [0: "abbbbbc" ,groups: undefined ,index: 0 ,input: "abbbbbcfhjkjhgabc" ,length: 1]
  var reg3 = new RegExp('ab*c', 'g') // /ab*c/g
  var res = reg3.exec('abbbbbcfhjkjhgabc')
  console.log('结果', res) // [0: "abbbbbc", groups: undefined, index: 0, input: "abbbbbcfhjkjhgabc", length: 1]
  • 全局检索与非全局检索得到的结果一致;
[2]test方法

(1)定义&作用
test方法是RegExp构造函数原型链上的一个方法,作用是:用于执行一个检索,用来查看正则表达式与指定的字符串是否匹配
(2)语法

  reg.test(str)
  // reg为定义的正则表达式
  // str为用来与正则表达式匹配的字符串

(3) 返回结果-boolean

  • 若是在str中找到匹配的 字符串,则返回true\
  • 否则返回false
    (4)示例
var reg2 = /ab*c/g
console.log(reg2.test('abbbbbcfhjkjhgabc')) // abbbbbc复合匹配---true
console.log(reg2.test('acbbbbbb')) // 没有复合匹配的字符---false
match方法

match方法是String构造函数原型上的方法,和exec方法类似

  • 相同点:在不使用全局匹配时,match方法与exec方法使用相同;
    • 若是存在匹配结果:返回第一个匹配的字符串的信息
    • 若是不存在匹配结果:返回null
  • 不同点:在进行全局匹配时
    • exec:与不全局匹配相同
    • match
      • 若是存在匹配结果:返回一个全部符合条件的字符串数组
      • 若是不存在匹配结果:返回null
应用
[1]应用1

应用:用户输入值后判断用户输入的值是否为x结尾且位数在10~20位之间

      var str = prompt('请输入')
      var reg = /.{9,19}x$/i
      console.log(reg.test(str), str) // true 12345678910x
[2]应用2

应用:检测一个字符是否以字母开头,由字母数字下划线组成且为10-20位

 var reg = /^[a-zA-Z]([a-zA-Z0-9_]{9-19})/
[3]应用3

应用:编写一个正则表达式匹配身份证号码

错误1-全局匹配&lastIndex属性
问题

看下面一个例子

      var reg2 = /ab{3,5}/g // 匹配一个a后面跟随了3~5个b的字符串
      console.log(reg2.test('abbbbbcfhjkjhgabc')) // true
      console.log(reg2.test('abbbbbcfhjkjhgabc')) // false
      console.log(reg2.test('abbbbbcfhjkjhgabc')) // true
      console.log(reg2.test('abbbbbcfhjkjhgabc')) // false
      console.log(reg2.test('abbbbbcfhjkjhgabc')) // true
      console.log(reg2.test('abbbbbcfhjkjhgabc')) // false
      console.log(reg2.test('abbbbbcfhjkjhgabc')) // true

同样的一个字符串,连续执行test方法,但是执行的结果不相同;

原因

正则表达式存在 lastIndex属性,该属性在进行全局匹配时才起作用。
如果正则表达式设置了全局标志,test() 的执行会改变正则表达式 lastIndex属性。连续的执行test()方法,后续的执行将会从 lastIndex 处开始匹配字符串,(exec() 同样改变正则本身的 lastIndex 属性值).

  • 若是匹配成功,lastIndex的值为匹配成功字符串的下一个字符的索引值;
  • 没有匹配成功,lastIndex的值重置为0;
  • lastIndex属性为可读可写的属性;

在上述代码中

  • 第一次执行,lastIndex为0,也就是从索引为0开始匹配;
  • 第一次执行结束, 匹配到abbbbb,lastIndex为6;
  • 第二次执行,lastIndex为6,也就是从索引为6开始匹配;
  • 第二次执行结束,没有匹配到正确的结果,lastIndex重置为0;
解决

[1]由于lastIndex为全局匹配时才有的,我们可以去掉全局匹配

      var reg2 = /ab{3,5}/ // 匹配一个a后面跟随了5个b的字符串
      console.log(reg2.test('abbbbbcfhjkjhgabc')) // true
      console.log(reg2.lastIndex) // 0
      console.log(reg2.test('abbbbbcfhjkjhgabc')) // true
      console.log(reg2.lastIndex) // 0

[2]lastIndex为可读可写的属性,我们可以在匹配成功之后将其重置为0

      var reg2 = /ab{3,5}/g // 匹配一个a后面跟随了5个b的字符串
      console.log(reg2.test('abbbbbcfhjkjhgabc')) // true
      reg2.lastIndex = 0
      console.log(reg2.test('abbbbbcfhjkjhgabc')) // true
常用正则
[1] 手机号
/^(1[3-9][0-9]{9})$/
[2] 汉字
/^[\u4E00-\u9FA5]{1,}$/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值