JS正则表达式

问题:

^ 符号,只有在 中括号里才算是取反吗?
  

learn from 珠峰正则表达式

JS正则表达式

正则表达式: regular express:(正则类: RegExp)

正则表达式是用来处理字符串的规则.

  1. 正则表达式, 只能处理字符串.

  2. 正则表达式是一个规则:

    • 可以验证字符串是否符合某个规则(test),
    • 也可以把字符串中符合规则的内容 捕获到 (exec/match)
    # test 匹配方法, 返回 布尔值
    let str = "good good study, day day up!"; 
    // => 学正则, 就是用来制定规则.
    let reg = /\d+/; // 是否包含数字
    reg.test(str) // false
    
    # exec 捕获方法. 
    str = "2021-07-10"
    reg.exec(str) // reg.js:7 ["2021", index: 0, input: "2021-07-10", groups: undefined]
    
编写正则表达式

正则表达式的创建方式有两种

  1. 字面量创建方式
  2. 构造函数模式创建(两个参数: 1. 元字符字符串, 2. 修饰符字符串)
//=> 字面量创建方式 (两个斜杠之间包起来的,都是用来描述规则的元字符)
let reg1=/\d+/;

//=> 构造函数创建. 两个参数: 元字符字符串(需要转义), 修饰符字符串
let reg2 = new RegExp("\\d+");

正则表达式 由 两部分组成

  • 元字符
  • 修饰符

我们要学好正则表达式, 就需要把这些元字符和修饰符背下来

元字符:

**元字符的分类包括 **

  1. 量词元字符
  2. 特殊元字符
  3. 普通元字符
量词元字符
#1. 量词元字符:  设置出现的次数. js 中常用的量词元字符有 6*  零到多次
+  一到多次
?  零次或一次
{n} 出现n次
{n,} 出现 n 到多次
{n,m} 出现 n 到 m 次
特殊元字符
#2. 特殊元字符:  单个或组合在一起代表特殊的含义
\				转义字符: 1. 把普通字符转换成有特殊含义的 2. 把特殊含义转换为普通字符

.				除 \n(换行符) 以外的任意字符

^				以哪一个元字符作为开始. 
$ 			以哪一个元字符作为结束

# --------------------------------------------
\n			换行符
\N			除换行符以外的任意字符(即 和 . 相同)
 
\d			0-9 之间的数字
\D0-9 之间的数字

\w			数字, 字母, 下划线中的任意一个字符
 \W			非 数字, 字母, 下划线中的任意一个字符
 
 \s			一个空白字符(包含, 空格, 制表符, 换页符)
 \S			
 
 \t			一个制表符(一个 TAB键盘: 四个空格)
 \b			匹配一个单词的边界
 
  
 # ----------------------------------------------

x|y				x 或者 y 中的一个字符 1|9|5
 
[xyz]			x或者y,或者 z 中的一个字符[adghve22] 取其中一个字符
[^xy]			除了 x 或y以外的任意字符
[a-z]    指定 a-z 这个范围中的任意字符[0-9a-zA-Z]  === \w
[^a-z]    取反. 除了 a-z以外的任意字符

 
 # 分组 =-=========================================
 ()				正则中的分组符号
 (?:)			只匹配不捕获
 (?=)			正向预查
 (?!)		  负向预查
普通元字符
 # =================================================
 #3. 普通元字符: 代表本身含义的字符
 /gene/ 正则匹配的就是 "gene" 本身含义

修饰符

正则表达式中常用的修饰符:

# 正则表达式中常用的修饰符 img
i		ignoreCase 忽略单词大小写匹配
m		multiline	忽略多行匹配, 可以进行多行匹配
g		global 全局匹配

元字符详解

$ 和 ^

^ 符号, 在 [] 中括号中是取反的意思,如下表示:

/[^?=&#]/g;	 // 表示除了 ? = & # 符号之外的任意符号.

$ ^

//let reg = /^a/;  // 以字母 a 开头
let reg = /^\d/; // 以数字开始
reg.test("gene");
reg.test("2021gene");
reg.test("gene2021")
let reg = /\d$/; // 以数字结束
reg.test("gene");
reg.test("2021gene");
reg.test("gene2021")
let reg = /\d+/; // 两个都不加, 字符串中, 包含符合规则的内容即可


let reg2 = /$\d$/ // 两个都加, 只能是和规则一致的内容.

#// 举个例子: 验证手机号码(11位, 第一个数字是 1 即可)
let reg = /^1\d{10}$/

\ 斜杠

转义字符:

  • 把特殊符号,转化为普通符号,
  • 或 把普通符号转化为特殊符号

注意: 字符串当中的一个斜杠, 也有特殊含义:

//=> . 不是小数点, 是除 \n 以外的任意字符.
let reg = /^2.3$/;
console.log(reg.test("2.3")) // true
console.log(reg.test("2@3")) // true
console.log(reg.test("23")) // fals 中间的点, 得占一个字符. 即匹配除 \n 换行符以外的任意一个字符. 

#----------------------------------
// 基于转义字符, 让其只能表示小数点
reg = /^2\.3$/;
console.log(reg.test("2.3")) // true
console.log(reg.test("2@3")) // false

let str = "\\d";    // 字符串里的 \ 斜杠, 也有转义的作用, 所以也需要做转义
let reg = /^\\d$/
reg.test(str)  // true

x|y 规则

x|y 规则

直接 x|y 会存在很乱的优先级问题, 一般我们写的时候, 都伴随着小括号进行分组, 因为小括号改变处理的优先级.

#// ----- 直接 x|y 会存在很乱的优先级问题, 一般我们写的时候, 都伴随着小括号进行分组, 因为小括号改变处理的优先级. 
# 小括号在正则表达式中叫做:  分组. 

let reg = /^18|29$/
console.log(reg.test("18")) //=true
console.log(reg.test("29"))//=true
console.log(reg.test("129"))//=true
console.log(reg.test("189")) //=true
console.log(reg.test("1829")) //=true
console.log(reg.test("829")) //=true
console.log(reg.test("182")) //=true

# ======== 分组 ==================
reg = /^(18|29)$/
console.log(reg.test("18")) //=true
console.log(reg.test("29"))//=true
console.log(reg.test("129"))//=false
console.log(reg.test("189")) //=false
console.log(reg.test("1829")) //=false
console.log(reg.test("829")) //=false
console.log(reg.test("182")) //=false

[] 规则

中括号中出现的字符, 大部分都表示本身含义.

  1. 中括号中出现的字符, 一般都代表本身的含义
  2. 中括号中, 不存在多位数
#// 1. 中括号中出现的字符, 一般都代表本身的含义.
let reg = /^[@+]+$/; // 这里中括号中的 + 号代表的就是 加 号本身
console.log(reg.test("@@"))
console.log(reg.test("@+"))

reg=/^[\d]$/  # //=> \d 在中括号中还是 0-9
console.log(reg.test("d"))
console.log(reg.test("\\"))
console.log(reg.test("9"))
# 中括号中不存在多位数
let reg = /^[18]$/
console.log(reg.test("1"))
console.log(reg.test("8"))
console.log(reg.test("18")) // false

reg=/^[10-29]$/; //=> 1 或者0-2或者9
console.log(reg.test("1"))
console.log(reg.test("9"))
console.log(reg.test("0"))
console.log(reg.test("2"))
console.log(reg.test("10")) // false

常用正则表达式

验证是否为有效数字

/**
 *规则分析
 * 1. 可能出现 + - 号, 也可能不出现 [+-]?
 * 2. 一位 0-9 都可以, 多位数 首位不能为 0 (\d|([1-9]\d+))
 * 3. 小数部分可能有, 可能没有, 一旦有, 后面必须有小数点 加 数字
 */

let reg = /^[+-]?(\d|([1-9]\d+))(\.\d+)?$/ 
// 匹配 十 到 二十 中间的数, 就用到了分组
let reg = /(10|11|12|13|14|15|16|17|18|19|20)?/
console.log(reg.test("10"))

验证密码

// => 数字字母,下划线
// 6~16位数.
let reg = /^\w{6,16}$/;

验证真实姓名的

/**
 * 规则:
 * 1. 汉字规则: /^[\u4E00-\u9FA5]$/ 
 *  "奥斯特洛夫斯基·拖拉机副司机"
 * 2. 名字长度 2-10 位
 * 3.可能有译名
 */
let reg = /^[\u4E00-\u9FA5]{2,10}(·[\u4E00-\u9FA5]{2,10}){0,2}$/; 

验证邮箱的

比较完善的邮箱规则, 开发中可以直接使用

// 邮箱的名字可以由数字字母下划线, - . 几部分组成. 但是 - 和 . 不能连续出现, 也不能作为开始

let reg = /^\w+((-\w+)|(\.\w+))*@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/;

//=> \w+((-\w+)|(\.\w+))* 
1. 开头是 数字字母下划线 (1到多次)
2. -数字字母下划线 或者 .数字字母下划线 (整体0-多次)

//=> @[A-Za-z0-9]+
1. @后面紧跟着数字字母, 可以使一到多位

//=> ((\.|-)[A-Za-z0-9]+)*
// 对 @ 符后面的名字的补充
1. .和数字字下划线出现 0 到 多次 或者 -和数字字母下划线出现0到多次

身份证号码

/**
 * 身份证号码规则
 * 1. 一共18位
 * 2. 最后一位可能是 X (大写X代表十)
 * 
 * 3. 身份证前六位: 省市县 130435
 * 4. 中间八位: 年月日
 * 
 * 最后四位: 
 * 6. 最后一位是 X 或者数字
 * 7. 倒数第二位 偶数是 女 奇数是男
 *    其余的是经过算法算出来的
 */


let reg = /^(\d{6})(\d{4})(\d{2})(\d{2})\d{2}(\d)(\d|X)$/;
reg.exec("130425199308090081");

// ["130425199308090081", "130425", "1993", "08", "09", "8", "1", index: 0, input: "130425199308090081", groups: undefined]
// 捕获的结果是一个数组, 包含每一个小分组单独获取的内容.

两种创建正则表达式的区别

  1. 构造函数因为传递的是字符串, \ 需要写两个才代表斜杠.
  2. 如果正则中要包含某个变量是的值, 则不能使用 字面量方式创建. 只能使用构造函数方式. (因为它传递的规则是字符串, 只有这样才能进行字符串拼接).
//=> 构造函数是因为传递的是字符串,  \ 需要写两个才代表斜杠.
let reg = /\d+/g;
reg = new RegExp("\\d+","g")

//=> 正则表达式中的 部分内容, 是变量存储的值. 
// 1.两个斜杠之间包起来的都是元字符.
// 2. 字面量创建正则的方式, 不能再中间加变量
let type = "gene";
let reg=/^@"+type+"@$/
console.log(reg.test("@gene@")) // false

let reg = new RegExp("^@"+type+"@$","g")
console.log(reg.test("@gene@"))  // true

正则的捕获方法

/**  正则捕获的懒惰性原因.
 * 懒惰性的原因就是: 默认情况下, lastIndex 的值是不会被修改的, 每一次都是从字符串开始位置查找, 所以找到的永远都只是第一个. 
 * let reg = /\d/
 * reg.lastIndex: 当前正则下一次匹配的起始索引位置.
 * 第一次匹配捕获完成, lastIndex没有改变, 所以下一次 exec 依然是从 字符串 0 的位置开始捕获, 找到的永远是 第一个匹配到的. 
 */

正则捕获的特点

正则捕获的特点:

  1. 正则捕获的懒惰性
  2. 正则捕获的贪婪性
正则捕获的懒惰性
正则捕获的贪婪性
  • 正则捕获的贪婪性: 默认情况下, 正则捕获的时候, 是按照当前正则所匹配的最长结果来捕获的. 如下面正则捕获的结果 ["2021", "2022"], 每次捕获都是捕获了最多的条件 20212022, 而不会单独捕获 2 0 2 这样单个捕获.
let str = "Gene2021@2022study"
let reg = /\d+/g;
console.log(str.match(reg)); //=>  ["2021", "2022"]


#// 取消正则匹配的贪婪性. 在量词元字符后面设置 ?号, 取消捕获时候的贪婪性. 按照正则匹配内容的最短结果来获取.
let str = "Gene2021@2022study"
let reg = /\d+?/g;
console.log(str.match(reg)); //=> ["2", "0", "2", "1", "2", "0", "2", "2"]

正则捕获的方法:

  1. 正则里面的方法: RegExp.prototype 上的方法
    • exec() 方法
    • test() 方法
  2. 字符串 String.prototype 上支持正则表达式处理的方法.
  • replace() 方法
  • match() 方法
  • splite() 方法
  • … …

exec 捕获

exec() 捕获是正则上的方法:

  1. 基于 exec 实现正则的捕获

    • 捕获到的结果是 null 或者 是一个数组.

      • 第一项: 是 本次捕获到的内容.

      • 其余项: 对应小分组单独捕获的内容

      • index: 当前捕获到的结果在字符串中起始索引.

      • input: 原始字符串.

    • 每执行一次 exec, 只能捕获到一个符合正则规则的内容, 但是默认情况下, 我们 执行 一百遍, 获取的结果永远都是第一个匹配到的, 其余的捕获不到. (正则捕获的懒惰性: 默认只捕获第一个)

let str = "Gene2021change2022life2023";
//=> 实现正则捕获的前提是: 当前正则要和字符串匹配. 如果不匹配, 捕获的结果是 null.

// 1. 把 str 中的所有的数字都匹配
let str = "Gene2021change2022life2023";
let reg = /\d+/;
console.log(reg.exec(str))
// 捕获的结果是一个数组: ["2021", index: 4, input: "Gene2021change2022life2023", groups: undefined]


# ----- 修饰符 ------------------------
// g 修饰符, 设置全局匹配符 g 后, 第一次匹配完, lastIndex 会自动修改. 
let str = "Gene2021change2022life2023";
let reg = /\d+/g;

注意:

# 注意: 
let reg = /\d+/g;

if(reg.test(str)){
  console.log(lastIndex); // 基于 test 匹配验证之后, lastIndex 已经被修改为第一次匹配后的索引结果, 所以下一次捕获不会再从头开始捕获了. 
  console.log(reg.exec(str)); 
}
实现一个 execAll 捕获所有的方法

🚩 需求: 编写一个 方法 execAll, 执行一次可以把所有匹配的结果捕获到.(前提: 正则一定要设置全局修饰符)

function execAll(str=""){
  // str: 要匹配的源字符串
  // this: RegExp 的实例(当前操作的正则)
  // arr 存储所有捕获的信息, res 存储每一次捕获的内容. 
  
  // 进来之后的第一件事, 是验证正则是否设置了 g, 不设置则不能进行循环捕获,  否则会导致死循环.
  if(!this.global) return this.exec(str)
  
 let arr = [],res=this.exec(str);
  while(res){
    // 只要捕获的内容不为 null, 则继续捕获
    arr.push(res[0]) // 把每一次捕获的内容存到 arr数组中
    res = this.exec(str)
  }
  return arr;
}

RegExp.prototype.execAll = execAll
let str = "Gene2021change2022life2023";
let reg = /\d+/g;

match 方法捕获

字符串中的match方法, 可以在执行一次的情况下, 捕获到所有匹配的数据(前提 正则也是全局匹配g才可以)

let str = "Gene2021change2022life2023";
let reg = /\d+/g;
console.log(str.match(reg))

test方法捕获

  1. test捕获方法. 基本不怎么用. test 本意识匹配
let str = "{2021}年{07}月{10}日";
let reg = /\{(\d+)\}/g;
console.log(reg.test(str))    // true
console.log(RegExp.$1)  // 2021

console.log(reg.test(str))  // true
console.log(RegExp.$1)  // 07

console.log(reg.test(str))  // true
console.log(RegExp.$1)  // 10

console.log(reg.test(str))  // false
console.log(RegExp.$1)  // 10 存储的是上一次捕获的结果

// RegExp.$1 ~ RegExp.$9; 获取当前本次匹配正则后, 第一个到第九个分组的信息. 

replace 方法捕获 很重要

replace 字符串中实现替换的方法.(一般都是伴随正则一起的)

let str = "gene@2021|gene@2022"
//=> 把字符串 "gene" 都替换成 "杨阳"

#//1. 不用正则,执行一次只能替换一个. 
str=str.replace("gene","杨阳");
console.log(str) // "杨阳@2021|gene@2022" 也是默认只替换一次. 


#//2. 使用正则会简单一点
let str = "gene@2021|gene@2022"
str=str.replace(/gene/g,"杨阳");
console.log(str)  // 杨阳@2021|杨阳@2022

需求

# replace 不用正则解决不了的问题.
let str = "gene@2021|gene@2022"

// 把 "gene" 替换成 "geneYang"
str=str.replace("gene","geneYang").replace("gene","geneYang")
console.log(str) // geneYangYang@2021|gene@2022  出现了问题. 每次都从第一个位置开始找. (类似于正则捕获的懒惰性)

# replace 使用正则解决问题
let str = "gene@2021|gene@2022"

// 把 "gene" 替换成 "geneYang"
str=str.replace(/gene/g,"geneYang")
console.log(str) // geneYang@2021|geneYang@2022 替换正确.

案例:

把时间字符串进行处理

let time = "2021-07-10";
//=> 变为 "2019年08月13日"
let reg=/^(\d{4})-(\d{1,2})-(\d{1,2})$/;

# //=> 这样可以实现
// time = time.replace(reg,"$1年$2月$3日")
// console.log(time) // 2021年07月10日

# ==================================
#// [str].replace([reg],[function])
// 1. 首先 那 reg 和 time 进行匹配捕获, 能匹配几次就会把传递的函数执行几次.(而且是匹配一次就执行一次)

//2. 不仅把方法执行, 而且 replace 还给方法传递了实参信息.(和exec捕获内容一致的信息:大正则匹配的内容, 小分组匹配的信息... ...)

// 3. 函数中 return 返回的内容,就是整个字符串替换后的内容.
/*
let time = "2021-07-10";
let reg=/^(\d{4})-(\d{1,2})-(\d{1,2})$/;
time=time.replace(reg,(big,$1,$2,$3)=>{
 // 这里的 $1 - $3是我们自己设置的变量
  console.log(big,$1,$2,$3);
})
// output: 2021-07-10 2021 07 10
*/

let time = "2021-07-10";
let reg=/^(\d{4})-(\d{1,2})-(\d{1,2})$/;
time=time.replace(reg,(big,...arg)=>{
 let [$1,$2,$3] = arg;
 $2.length<2?$2="0"+$2:null;
 $2.length<2?$3="0"+$3:null;
 return $1+"年"+$2+"月"+$3+"日"
})

案例:

验证一个字符串中哪个字母出现的次数最多, 出现多少次?

let str = "good good study, day day up hahahaha";
let obj={};
[].forEach.call(str,char=>{
  if(char in obj){
    obj[char]++;
    return
  }
  obj[char]=1;
})
console.log(obj)

正则表达式之时间字符串格式化

//=> 服务器获取的时间字符串的格式
// "2021-07-10 18:34:3"
// "2021/0710 18:34:3"

//=> 想要转变的格式
// "07月10日 18时34分"
// "2021年07月10日"

// 时间字符串格式化处理.
!function(){
  /**
   * formatTime: 时间字符串的格式化处理
   */
  function formatTime(){
    //1. 首先获取时间字符串中的, 年月日等信息
   let timeAry = this.match(/\d+/g);
    console.log(timeAry)
    let template = "{0}年{1}月{2}日 {3}时{4}分{5}秒"
    template=template.replace(/\{(\d+)\}/g,(content,$1)=>{
      // content: 当前匹配大正则匹配的信息, $1 本次单独匹配小分组匹配的信息
      let time=timeAry[$1] || "00";
      time.length<2 ? time="0"+time:null;
      
    });
    return template;
  } 
  
  /* 扩展到内置类 String.prototype上 */
  // 这样的写法可以往原型上扩展多个方法,只需要在数组里添加字符串就可以了.
  ["formatTime"].forEach((item)=>{
    String.prototype[item]=eval(item)
  })
  
}();

? 号在正则中的五大作用

  1. 问号左边是 非 量词元字符:本身代表量词, 表示出现 0 到 一次.
  2. 问号左边是量词元字符: 取消捕获时候的贪婪性
  3. (?: ) 只匹配不捕获.
  4. (?=) 正向预查
  5. (?!) 负向预查

分组的作用

  1. 分组的第一个作用: 改变优先级
  2. 分组的第二个作用: 分组捕获.
    • 不仅可以把大正则匹配的信息捕获到,
    • 还可以单独捕获到每个小分组的内容.

learn from 珠峰正则表达式:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
智慧校园整体解决方案是响应国家教育信息化政策,结合教育改革和技术创新的产物。该方案以物联网、大数据、人工智能和移动互联技术为基础,旨在打造一个安全、高效、互动且环保的教育环境。方案强调从数字化校园向智慧校园的转变,通过自动数据采集、智能分析和按需服务,实现校园业务的智能化管理。 方案的总体设计原则包括应用至上、分层设计和互联互通,确保系统能够满足不同用户角色的需求,并实现数据和资源的整合与共享。框架设计涵盖了校园安全、管理、教学、环境等多个方面,构建了一个全面的校园应用生态系统。这包括智慧安全系统、校园身份识别、智能排课及选课系统、智慧学习系统、精品录播教室方案等,以支持个性化学习和教学评估。 建设内容突出了智慧安全和智慧管理的重要性。智慧安全管理通过分布式录播系统和紧急预案一键启动功能,增强校园安全预警和事件响应能力。智慧管理系统则利用物联网技术,实现人员和设备的智能管理,提高校园运营效率。 智慧教学部分,方案提供了智慧学习系统和精品录播教室方案,支持专业级学习硬件和智能化网络管理,促进个性化学习和教学资源的高效利用。同时,教学质量评估中心和资源应用平台的建设,旨在提升教学评估的科学性和教育资源的共享性。 智慧环境建设则侧重于基于物联网的设备管理,通过智慧教室管理系统实现教室环境的智能控制和能效管理,打造绿色、节能的校园环境。电子班牌和校园信息发布系统的建设,将作为智慧校园的核心和入口,提供教务、一卡通、图书馆等系统的集成信息。 总体而言,智慧校园整体解决方案通过集成先进技术,不仅提升了校园的信息化水平,而且优化了教学和管理流程,为学生、教师和家长提供了更加便捷、个性化的教育体验。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值