# 正则表达式

# 什么是正则表达式 — 介绍

  • 正则表达式 (Regular Expression) 是用于匹配字符串中字符组合的模式。在 JavaScript 中,正则表达式也是对象.
  • 通常用来查找替换那些符合正则表达式的文本,许多语言都支持正则表达式。

image-20230804161403056

请在上图中找出 [戴帽子眼镜男人]

戴帽子,戴眼镜,男人 都是描述信息,通过这些信息能够在人群中查找到确定的某个人,那么这些用于查找的描述信息编写一个模式,对应到计算机中就是所谓的正则表达式。

  • 正则表达式在 JavaScript 中的使用场景
  • 例如验证表单:用户名表单只能输入英文字母,数字或者下划线,昵称输入框中可以输入中文 (匹配)
    • 比如用户名/^[a-z0-9_-]{3,16}$/
  • 过滤掉页面内容中的一些敏感词 (替换),或从字符串中获取我们想要的特定部分 (提取) 等。

# 总结

1 正则表达式是什么?

  • 是用于匹配字符串中字符组合的模式.

2 正则表达式有什么作用?

  • 表单验证 (匹配)
  • 过滤敏感词 (替换)
  • 字符串中提取我们想要的部分 (提取)

# 语法

image-20230804162216036

我们想要查找是否有戴眼镜的人,怎么做呢

  1. 定义规则:戴眼镜的
  2. 根据规则去查找:找到则返回

正则同样道理,我们分为两步

  1. 定义规则
  2. 查找

比如:查找下面文本中是否包含字符串 "前端"

let str = 'IT培训,前端开发,web前端,软件测试,产品经理,前端'

JavaScript 中定义正则表达式的语法有两种。

# 1 定义正则表达式语法:

const 变量名 = /表达式/
  • 其中 / / 是正则表达式字面量.

  • 比如:

const reg = /前端/

# 2 判断是否有包含规则的字符串

test() 方法,用来查看正则表达式与指定的字符串是否匹配

  • 语法
regObj.test(被检测的字符串)
  • 秒记 法则: 现有规则,再去检查

  • 比如:

const str = 'IT培训,前端开发,web前端,软件测试,产品经理,前端'
// 正则表达式使用
// 1. 定义规则
const reg = /前端/
// 2. 匹配
console.log(reg.test(str))
  • 如果正则表达式与指定的字符串匹配,返回 true,否则 false.

结果

image-20230804163519183

# 3 检索 (查找) 符合规则的字符串

exec () 方法 是一个指定字符串中执行一个搜索匹配

如果匹配成功,exec () 方法返回一个数组,否则返回 null

  • 语法
regObj.exec(被检测字符串)
  • 比如
const str = 'IT培训,前端开发,web前端,软件测试,产品经理,前端'
// 正则表达式使用
// 1. 定义规则
const reg = /前端/
// 2. 检索 返回的是一个数组
console.log(reg.exec(str))

结果

image-20230804164151228

# 总结

1 正则表达式检测查找 test 方法和 exec 方法有什么区别?

  • test 方法,用于判断是否有符合规则的字符串,返回的是布尔值,找到返回 true,否则 false
  • exec 方法 用于检索 (查找) 符合规则的字符串,找到返回数组,否则为 null

# 元字符

普通字符 (麻烦):

大多数的字符仅能够描述它们本身,这些字符称作普通字符,例如所有的字母数字

也就是说普通字符只能够匹配字符串中与它们相同的字符

元字符 (特殊字符 比较轻松)

是一些具有特殊含义的字符,可以极大提高了灵活性强大的匹配功能

  • 比如,规定用户输入英文 26 个英文字母,普通字符的话 abcdefghijklm....
  • 但是换成元字符写法:[a-z] 就是 a 到 z 的 26 个英文字母

# 总结

什么是元字符以及它的好处是什么?

  • 是一款具有特殊含义的字符,可以极大提高了灵活性和强大的匹配功能
  • 比如英文 26 个英文字母,我们使用元字符 [a-z] 简介和灵活

# 为了方便记忆和学习,我们对众多的元字符进行了分类:

  • 边界符 (表示位置,开始和结尾,必须用什么开头,用什么结尾)
  • 量词 (表示重复次数)
  • 字符类 (比如 \d 表示 0 ~ 9)

# 1 边界符

  • 正则表达式中的边界符 (位置符) 用来提示字符所处的 位置,主要有两个字符.
边界符说明
^表示匹配行首的文本 (以谁开始)
$表示匹配行尾的文本 (以谁结束)

如果 ^$ 在一起同时使用,表示必须是精确匹配。

代码

console.log("----------------")
// 元字符
console.log("--------元字符--------")
console.log(//.test('哈')) //true
console.log(//.test('哈哈'))//true
console.log(//.test('二哈'))//true
console.log("--------边界符--------")
// 边界符 
// ^ 以谁开始 以哈开始
console.log("--------^ 以谁开始 以哈开始--------")
console.log(/^哈/.test('哈'))//true
console.log(/^哈/.test('哈哈'))//true
console.log(/^哈/.test('二哈'))//false
// $ 以谁结尾 以哈结尾
console.log("--------$以谁结尾 以哈结尾--------")
console.log(/哈$/.test('哈'))//true
console.log(/哈$/.test('哈哈'))//true
console.log(/哈$/.test('哈二'))//false
// 以谁开始 以谁结尾 以哈开始 以哈结尾
// ^$ 一起使用就是精确匹配 只有这种写法为 true 其余都是 false
console.log("--------精确匹配 (^$)--------")
console.log(/^哈$/.test('哈'))//true
//^$ 写法是精确匹配 要求里面就是一个 哈 两个哈 / 一个以上 就 false
console.log(/^哈$/.test('哈哈'))//false
console.log(/^哈$/.test('二哈二'))//false
console.log("----------------")

效果

image-20230804171744848

# 2 量词

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

量词说明
*重复零次或更多次
+重复一次或更多次
?重复零次或一次
{n}重复 n 次
{n,}重复 n 次或更多次
{n,m}重复 n 到 m 次

注意:<font color=red> 逗号左右两侧千万不要出现空格 </font>.

代码

console.log('-----------*-----------')
console.log(/^哈*$/.test('哈哈')) //true
console.log(/^哈*$/.test('')) //true
console.log(/^哈*$/.test('哈哈哈')) //true
// 精确匹配内容必须只能是 哈 不能出现其它的字符
console.log(/^哈*$/.test('哈二哈')) //false
console.log(/^哈*$/.test('哈二哈很')) //false
console.log(/^哈*$/.test('很二哈')) //false
console.log('-----------+-----------')
console.log(/^哈+$/.test('哈')) //true
console.log(/^哈+$/.test('哈哈')) //true
console.log(/^哈+$/.test('')) //false
console.log(/^哈+$/.test('哈哈二')) //false
console.log(/^哈+$/.test('哈二哈')) //false
console.log(/^哈+$/.test('二哈哈')) //false
console.log('-----------?-----------')
console.log(/^哈?$/.test('哈')) //true
console.log(/^哈?$/.test('')) //true
console.log(/^哈?$/.test('哈哈')) //false
console.log(/^哈?$/.test('哈哈二')) //false
console.log(/^哈?$/.test('二哈哈')) //false
console.log(/^哈?$/.test('二哈')) //false
console.log('-----------{n}-----------')
console.log(/^哈{3}$/.test('哈')) //false
console.log(/^哈{3}$/.test('哈哈')) //false
console.log(/^哈{3}$/.test('哈哈哈')) //true
console.log(/^哈{3}$/.test('哈哈哈哈')) //false
console.log('-----------{n,}-----------')
console.log(/^哈{3,}$/.test('哈')) //false
console.log(/^哈{3,}$/.test('哈哈')) //false
console.log(/^哈{3,}$/.test('哈哈哈')) //true
console.log(/^哈{3,}$/.test('哈哈哈哈')) //true
console.log(/^哈{3,}$/.test('哈哈哈哈哈')) //true
console.log('-----------{n,m}-----------')
//3 到 4 之间都是 true 其余都是 false (3,4 之间不要加空格 否则出错)
console.log(/^哈{3,4}$/.test('哈')) //false
console.log(/^哈{3,4}$/.test('哈哈')) //false
console.log(/^哈{3,4}$/.test('哈哈哈')) //true
console.log(/^哈{3,4}$/.test('哈哈哈哈')) //true
console.log(/^哈{3,4}$/.test('哈哈哈哈哈')) //false

结果

image-20230804174848021

image-20230804174901156

image-20230804174912438

# 总结

+ 表示重复至少 1 次或更多次 等价于 {1,}

? 表示重复 0 次或 1 次 等价于 {0,1}

* 表示重复 0 次或多次 等价于 {0,}

{n,m} 表示重复 n 到 m 次

所以建议 使用 {} 形式书写 量词 比较方便 且 统一

# 3 字符类

[ ] 匹配字符集合

  • 后面的字符串只要包含 abc任意一个字符,都返回 true
// 只要括号里面的任意字符出现都返回 true
console.log(/[abc]/.test('andy')) //true
console.log(/[abc]/.test('bady')) //true
console.log(/[abc]/.test('cry')) //true
console.log(/[abc]/.test('die')) //false

/^[abc]$/ 匹配字符 ^$ 在一起就是精确匹配 只选 abc 其中一个 出现多个为 false

console.log(/^[abc]$/.test('a')) //true
console.log(/^[abc]$/.test('b')) //true
console.log(/^[abc]$/.test('c')) //true
console.log(/^[abc]$/.test('ab')) //false 
console.log(/^[abc]$/.test('abc')) //false
console.log(/^[a-zA-Z0-9-_]$/.test('a')) //true
console.log(/^[a-zA-Z0-9-_]$/.test('A')) //true
console.log(/^[a-zA-Z0-9-_]$/.test('_')) //true
console.log(/^[a-zA-Z0-9-_]$/.test('aA')) //false
console.log(/^[a-zA-Z0-9-_]$/.test('aA_')) //false

可以配合量词使用就可以规定 [ ] 中包含的 字符出现 多少次了

console.log(/^[abc]$/.test('a')) //true
console.log(/^[abc]$/.test('b')) //true
console.log(/^[abc]$/.test('c')) //true
console.log(/^[abc]{2}$/.test('ab')) //true
console.log(/^[abc]{1,3}$/.test('abc')) //true 
console.log(/^[a-zA-Z0-9-_]{6,16}$/.test('aabbcAB12__')) //true
console.log(/^[a-zA-Z0-9-_]{6,16}$/.test('aabbcAB12__@')) //false

[ ] 里面加上 - 连字符.

  • 使用连字符 - 表示一个范围.
console.log(/^[a-z]$/.test('c')) // true
  • 比如
    • [a-z] 表示 a 到 z,26 个英文字母 其中一个都可以
    • [a-zA-Z] 表示大小写都可以
    • [0-9] 表示 0~9 的数字都可以
  • 认识下
  • 第一位是 1~9 第二位是 0~9 四位或者更多位 量词重复的是它傍边的字符类
QQ: ^[1-9][0-9]{4,}$ (QQ号从10000开始)

[ ] 里面加上 ^ 取反符号

  • 比如
    • [^a-z] 匹配除了小写字母以外的字符
    • 注意要写到中括号里面,写在 /[^ ]/ 中的 ^ 就是取反的意思,写在 /^[]/ 中的 ^ 就是以什么开头的意思。
console.log(/[^abc]$/.test('a')) //false

. 匹配除换行符之外的任何字符

  • 比如
    • 可以用来避免用户输入换行
    • 除了换行符其它字符都为 true
console.log(/./.test('\n')) //false

# 3.1 预定义

预定义:指的是某些常见的简写方式.

预定类说明
\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]
日期格式:^\d{4}-\d{1,2}-\d{1,2}$

# 用户表单验证案例

代码

html

<body>
    <input type="text">
    <span></span>
    <script src="./js/验证用户名案例.js"></script>
</body>

css

<style>
        span {
            display: block;
            width: 250px;
            height: 30px;
            line-height: 30px;
            padding-left: 15px;
        }
        .error {
            margin: 3px;
            color: red;
            background: url(./images/error1.png) no-repeat left center;
        }
        .right {
            margin: 3px;
            color: green;
            background: url(./images/right.png) no-repeat left center;
        }
    </style>

js

// 创建正则表达式
const reg = /^[a-zA-Z0-9-_]{3,}$/
// 获取元素对象
const inputText = document.querySelector('input[type="text"]')
// 获取上面的元素的兄弟标签对象
const span = inputText.nextElementSibling
// 绑定 离焦事件 
inputText.addEventListener('blur', function () {
    // 判断规则
    if (reg.test(this.value)) {
        span.innerHTML = '输入正确'
        span.className = 'right'
    }
    else {
        span.innerHTML = '输入错误'
        span.className = 'error'
    }
})

# 4 修饰符

修饰符约束正则执行的某些细节行为,如是否区分大小写,是否支持多行匹配等

/表达式/修饰符
  • i 是单词 ignore (翻译:忽略) 的缩写,正则匹配时字母不区分大小写.
  • g 是单词 global (翻译:全局) 的缩写,匹配所有满足正则表达式的结果.
  • i 与 g 可以组合使用 i 不区分大小写,g 全局查找。
  • 比如 如下
console.log(/a/i.test('a')) //true 
console.log(/a/i.test('A')) //true

代码

console.log(/^java$/.test('java'))//true
console.log(/java/i.test('Java'))//true
console.log(/^java$/i.test('JAVA'))//true
console.log(/^java$/.test('java'))//true
console.log(/^java$/g.test('JAVA'))//false
console.log(/java/g.test('Java'))//false

结果

image-20230805091743864

# 4.1 替换 replace 替换

语法

字符串.replace(/正则表达式/,'替换的文本')

代码

  • 默认只会查找出一个
const str = 'java是一门编程语言,记住是JAVA'
//i 不区分大小写,g 全局查找 可以组合使用 不区分大小查找全部匹配的字符
const result = str.replace(/java/i,'前端')
console.log(result)

效果

image-20230805092645841

  • 使用 i 不区分大小写,g 全局查找 组合
const str = 'java是一门编程语言,记住是JAVA'
//i 不区分大小写,g 全局查找 可以组合使用 不区分大小查找全部匹配的字符
const result = str.replace(/java/ig,'前端')
console.log(result)

效果

image-20230805092737945

# 4.2 使用 | 运算符

  • 同时满足判断的。
const str = 'java是一门编程语言,记住是JAVA'
// 不使用 i 区分大小写 可以使用 | 运算符 来判断是否满足匹配条件
const result = str.replace(/java|JAVA/g,'前端')
console.log(result)

# 综合案例 — 注册页面

需求 1

发送验证码

用户点击之后,显示 05 秒后重新获取

时间到了,自动改为 重新获取

image-20230805135248377

需求 2

用户名验证 (注意封装函数 verifyxxx),失去焦点触发这个函数

正则 /^[a-zA-Z0-9_]{6,10}$/

如果不符合要求,则出现提示信息,并 return false 中断程序

否则 则返回 return true

之所以返回 布尔值,是为了 最后的提交按钮做准备

监听使用 change 事件,当鼠标离开了标签,并且表单值发生了变化时触发事件,不要使用 blue 离焦事件,那样用户并没有输入任何东西只是点了一下又点了其它位置就会触发事件很浪费资源的。