Js正则表达式

362 阅读7分钟

概念

对正则表达式的理解,什么是正则怎么定义它,作用是什么?

正则表达式是用于匹配字符串中字符组合的模式。在 JavaScript 中,正则表达式也是对象。这些模式被用于 RegExpexectest 方法,以及 StringmatchmatchAllreplacesearchsplit 方法。

创建正则

创建正则表达式有字面量方式和构造函数实例的方式

字面量声明正则表达式 使用两个斜杠 // 之间 写入匹配模式

let reg = /^\d+$/g

调用 RegExp对象的构造函数声明实例创建正则

//构造函数创建的正则,第一参数可以是字符串形式的正则,不再包含//双斜杠
let reg = new RegExp("[0-9z-a]{1,}",'g')
//从 ECMAScript 6 开始,第一个参数也可以是一个字面量正则表达式
let reg = new RegExp(/^[a-z]$/)

实例创建需要注意的事项

1.遇到带有/的特殊字符 要多加一个\

//对于\d \w \n...这些都需要多加一个,使其扔保持特殊字符的意义
let reg  = new RegExp('^\d+$')
reg.test('2022') //-> false
let reg1  = new RegExp('^\\d+$')
reg1.test('2022') //-> true
//在构造函数创建正则,只要出现,基本都要写\。
let reg = /^[2022]$/ //-> '[2022]'
reg.test('[2022]') //->true
let reg1 = new RegExp('^[2022]$')
reg1.test('[2022]') //->false
let reg2 = new RegExp('^\[2022\]$')
reg3.test('[2022]') //->true

2.包含有[] ()类的元字符,在实例正则参数里 没有区别扔保持原有意义

let reg = /^\d+$/
reg.test(12312) //-> true
let reg1 = new RegExp("^[0-9]+$");
reg1.test(12234) //->true

动态变量正则

正则表达式中需要把一个变量的值作为一个动态的规则,只能使用构造函数创建的方式

//'[2022]'
let num = 2022;
var reg = new RegExp("^\[" + num + "\]$");
console.log(reg.test("[2022]"));//->true

修饰符

标志描述
g全局搜索。
i不区分大小写搜索。
m多行搜索。
s允许 . 匹配换行符。
u使用 unicode 码的模式进行匹配。
y执行“粘性 (sticky)”搜索,匹配从目标字符串的当前位置开始。

修饰符 /g 的使用

首先test()方法慎用修饰符 g,加g 以后 正则对象会将字符串按照全局搜索匹配,正则对象有一个特别的实例属性lastIndex,表示的是下一次搜索开始的位置。加g后正则里的lastIndex属性一直在变,导致下次匹配返回的不是真实的结果

let reg = /^\d+$/
reg.test(2022) //->true
reg.test(2022) //->true
reg.lastIndex //-> 0 不加g lastIndex不会改变,所有返回结果不变

//加g以后
let reg1 = /^\d+$/g
reg1.test(2022) //->true
reg1.lastIndex //-> 4 第一轮匹配完后 变为4
reg1.test(2022) //->false 搜索会从下标4开始,不会在乎里面的2022的值,所以查不到返回false
reg1.lastIndex //->0 false以后下标会重新变为0 
reg.test(2022) //-> true 值再次返回true 

修饰符 /i 的使用 加i 以后不再区分大写的匹配

let reg = /^[a-z]+$/
reg.test('ABC') //=>false

let reg1 = /^[a-z]+$/i
reg1.test('ABC') //->true

元字符

特殊意义元字符

\d[0-9]匹配数字0-9任意一个
\D[^0-9]匹配非 0-9 任意一个
\s匹配所有空白符
\S匹配所有非空白符
\w[0-9a-zA-Z_] 匹配任意一个0-9A-Za-z_字符
\W匹配非单词字符 [^0-9a-zA-Z_]
\n匹配换行符
\转译字符 特殊字符想要代表本身 需要使用转译字符 . 仅代表字符点,不再代表任意字符
.匹配非\n 任意一个字符
匹配开头字符串
$匹配结尾字符串
x|y匹配字符包含x或者y的一个
[xyz]匹配xyz其中任意一个
[a-z]匹配a-z中任意一个字符
[^a-z]匹配非 a-z任意一个
[^0-9]匹配非 0-9 的任意一个字符
[0-9]匹配0-9任意一个字符
[\u4e00-\u9fa5]匹配任意一个汉字字符
()大正则中小分组,区分优先级

[10-23] 中括号里面短横线代表连字符匹配 1 0-2 3,如果想单纯匹配短横线 放到末尾 [0-9-] // 4-

中括号里出现的位数不是两位数,而是并列关系[12] // 1或2 其中一个

中括号本身也需要转译 /^[\d+]$ / //-> [100]

在中括号中 所有字符都代表字符本身,不再特殊。

量词元字符

*{0,} 匹配0到多个字符
+匹配1到多个字符 {1,}
匹配0到1个字符 {0,1}
{n,}匹配n到多个字符
{n,m}匹配n到m个字符
{n}匹配n个字符

正则相关方法

方法描述
exec一个在字符串中执行查找匹配的 RegExp 方法,它返回一个数组(未匹配到则返回 null)。
test一个在字符串中测试是否匹配的 RegExp 方法,它返回 true 或 false。
match一个在字符串中执行查找匹配的 String 方法,它返回一个数组,在未匹配到时会返回 null。
matchAll一个在字符串中执行查找所有匹配的 String 方法,它返回一个迭代器(iterator)。
search一个在字符串中测试匹配的 String 方法,它返回匹配到的位置索引,或者在失败时返回-1。
replace一个在字符串中执行查找匹配的 String 方法,并且使用替换字符串替换掉匹配到的子字符串。
split一个使用正则表达式或者一个固定字符串分隔一个字符串,并将分隔后的子字符串存储到数组中的 String 方法。

就把常用的列举下

test

let str = 'hello world!';
let result = /^hello/.test(str);
console.log(result);
// true

match

字符串的方法,参数是正则表达式

const paragraph = 'The quick brown fox jumps over the lazy dog. It barked.';
const regex = /[A-Z]/g;
const found = paragraph.match(regex); //-> ['T','I']

//不加g 的匹配
const reg = /[A-Z]/;
const found1 = paragraph.match(reg);
//['T', index: 0, input: 'The quick brown fox jumps over the lazy dog. It barked.', groups: undefined]

//匹配不成功 返回null
const reg1 = /[A-C]/;
const found2 = paragraph.match(reg1); //->null

//使用match不传参数 返回
var str = "Nothing will come of nothing.";
str.match();   // returns [""]

replace

该方法并不改变调用它的字符串本身,而只是返回一个新的替换后的字符串。

在进行全局的搜索替换时,正则表达式需包含 g 标志。

//str.replace(regexp|substr, newSubStr|function)
//第一参数是需要替换的模式,可以是一个字符串或者一个正则表达式
//第二参数替换值可以是一个字符串或者一个每次匹配都要调用的回调函数
const p = 'The quickthe lazy dog. If the dog reacted';
const regex = /Dog/i;
console.log(p.replace(regex, 'ferret'))
//仅替换第一个匹配项
//-> The quickthe lazy ferret. If the dog reacted

//加g 以后
const regex1 = /Dog/ig;
console.log(p.replace(regex1, 'ferret'))
//匹配全局
//-> The quickthe lazy ferret. If the ferret reacted
//交换字符串中的两个单词
var re = /(\w+)\s(\w+)/;
var str = "John Smith";
var newstr = str.replace(re, "$2, $1");
// Smith, John
console.log(newstr);

常用正则

常见的表单验证

// 用户名正则,4到16位(字母,数字,下划线,减号)
var userNameReg = /^[a-zA-Z0-9_-]{4,16}$/;

// 密码强度正则,最少6位,包括至少1个大写字母,1个小写字母,1个数字,1个特殊字符
var passwordReg = /^.*(?=.{6,})(?=.*\d)(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#$%^&*? ]).*$/;

// 匹配邮箱地址
var mailReg = /\w+([-+.]\w+)*@\w+([-.]\w+)*.\w+([-.]\w+)*/;

// 中国六位数的邮政编码
var postalCode = /^\d{6}$/;

// 匹配15~18位身份证
var IDCard = /(^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$)|(^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{2}$)/;

// 匹配18位的新版身份证
var IDCard_18 = /^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/;

网络相关

//ipv4地址正则
var IPReg = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;

// Reg Hex颜色正则
var pattern = /^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/;

// URL正则
var urlReg= /^((https?|ftp|file)://)?([\da-z.-]+).([a-z.]{2,6})([/\w .-]*)*/?$/;

// 匹配JSON格式
var reg = /^\w+(({[^()]+}))$/

匹配json字符串

var ret = response.data;
if (typeof ret === 'string') {
  var reg = /^\w+(({[^()]+}))$/
  var matches = ret.match(reg);

  if (matches) ret = JSON.parse(matches[1]);
}
res.json(ret);

匹配特定数字

// 匹配正整数
var reg = /^[1-9]\d*$/;

// 匹配负整数
var reg = /^-[1-9]\d*$/;

// 匹配整数
var reg = /^-?[1-9]\d*$/;

// 匹配非负整数(正整数 + 0)
var reg = /^[1-9]\d*|0$/;

// 匹配非正整数(负整数 + 0)
var reg = /^-[1-9]\d*|0$/;

// 匹配正浮点数
var reg = /^[1-9]\d*.\d*|0.\d*[1-9]\d*$/;

// 匹配负浮点数
var reg = /^-([1-9]\d*.\d*|0.\d*[1-9]\d*)$/;

// 匹配浮点数
var reg = /^-?([1-9]\d*.\d*|0.\d*[1-9]\d*|0?.0+|0)$/;

// 匹配非负浮点数(正浮点数 + 0)
var reg = /^[1-9]\d*.\d*|0.\d*[1-9]\d*|0?.0+|0$/;

// 匹配非正浮点数(负浮点数 + 0)
var reg = /^(-([1-9]\d*.\d*|0.\d*[1-9]\d*))|0?.0+|0$/;

字符串相关

// 匹配由26个英文字母组成的字符串
var reg = /^[A-Za-z]+$/;

// 匹配由26个英文字母的大写组成的字符串
var reg = /^[A-Z]+$/;

// 匹配由26个英文字母的小写组成的字符串
var reg = /^[a-z]+$/;

// 匹配由数字和26个英文字母组成的字符串
var reg = /^[A-Za-z0-9]+$/;

// 匹配由数字、26个英文字母或者下;划线组成的字符串
var reg = /^\w+$/;

// 匹配空白行的正则表达式
var reg = /\n\s*\r/;

// 匹配首尾空白字符的正则表达式
var reg = /^\s*|\s*$/;
var rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;

// 匹配双字节字符(包括汉字在内, 一个双字节字符长度计2,ASCII字符计1)
var reg = /[^\x00-\xff]/g;

验证邮箱

// 371778059@qq.com
// 371778059@163.com.cn
// 371778059@163.com
//var reg7 = /^[\w.-]+@$/  //@分解两边 左边任意,\w 数字,大小写字符_ - . 右边
var reg7 = /^[\w.-]+@([1-9]|[a-z]|[A-Z])+(.[A-Za-z]{2,4}){1,2}$/
console.log(reg7.test('371778059@qq.com'))

function validEmail(email) {
  const reg = /^(([^<>()[]\.,;:\s@"]+(.[^<>()[]\.,;:\s@"]+)*)|(".+"))@(([[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}])|(([a-zA-Z-0-9]+.)+[a-zA-Z]{2,}))$/
  return reg.test(email)
}

验证有效数字的

  0 -12 -12.3 -12.0 12.3 12.0
    ->可能出现"-"也可能不出现,出现的话只能出现一次
    ->整数部分是一到多个数字,但是两位数及以上的话不能以0开头
    ->小数部分可能有可能没有,一但有必须是 .后面跟一位或者多位数字
    var reg = /^-?(\d|([1-9]\d+))(.\d+)?$/;

格式化时间字符串

var str = "2016-04-03";//->"20160403日"
let reg = /^([1-9]\d{3})-(0?[1-9]|1[1-2])-([012]\d|[3][0-1])$/

人民币格式化

const moneyFormat = num => {
	return num.toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}

const formatMoney = (money) => {
  return money.replace(new RegExp(`(?!^)(?=(\d{3})+${money.includes('.') ? '\.' : '$'})`, 'g'), ',')  
}

解析参数

const parseQuery = (name, queryStr) => {
	const reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i")
	if (!wx && !queryStr) {
		queryStr = location.search.substr(1)
	} else if (wx && !queryStr) {
		return null
	} else if (wx && queryStr && queryStr.includes('?')) {
		queryStr = queryStr.split('?')[1]
	}
	let r = queryStr.match(reg)
	if (r != null) {
		return decodeURIComponent(r[2])
	}
	return null
}


export const getQuery = (path) => {
	const result = {}, param = /([^?=&]+)=([^&]+)/ig;
	let match = true
	if (!path) return result
	while ((match = param.exec(path)) !== null) {
		result[match[1]] = decodeURIComponent(match[2]);
	}
	return result;
}

filter 金额小数点两位

export const clearNum = (value) => {
	let filterValue = value.toString();
	filterValue = filterValue.replace(/[^\d.]/g, "");  //清除“数字”和“.”以外的字符
	filterValue = filterValue.replace(/^./g, "");  //  不能以“.”开头
	filterValue = filterValue.replace(/(^[0]{2,})|(^[0][1-9])/g, "0"); //首位不能为类似于 01、02的金额
	filterValue = filterValue.replace(/.[0]{2,}/g, ".0"); //. 后面不能有连续的0
	filterValue = filterValue.replace(/.{2,}/g, "."); //只保留第一个. 清除多余的
	filterValue = filterValue.replace(".", "$#$").replace(/./g, "").replace("$#$", ".");//保证.只出现一次,而不能出现两次以上
	filterValue = filterValue.replace(/^(-)*(\d+).(\d\d).*$/, '$1$2.$3');//只能输入两个小数
	return filterValue;
}

软件版本号校验

	const flag = /^\d+\.\d+\.?\d*$/.test('1.0') //true
        const flag = /^\d+\.\d+\.?\d*$/.test('1.0.4') //true
        const flag = /^\d+\.\d+\.?\d*$/.test('1.0.3.32') //false

汉字替换为字符

	const newValue = value?.replace(/[\u4e00-\u9fa5]/gu, 'aa')

验证密码强度

//密码长度为8-20个字符,需同时包含数字、字母以及特殊符号等非空格
function validPassword(pwd) {
  const reg = /^(?=.*[A-Za-z])(?=.*\d)(?=.*[`~!@#$%^&*()_+<>?:"{},./\;'[]])[A-Za-z\d`~!@#$%^&*()_+<>?:"{},./\;'[]]{8,20}$/
  return reg.test(pwd)
}

判断url是否是http或https

function isHttp(url = '') {
  return /^http(s)?:///.test(url)
}

//判断path是否为外链
function isExternal(path) {
  return /^(https?:|mailto:|tel:)/.test(path)
}

//判断URL合理
function validURL(url) {
  const reg = /^(https?|ftp)://([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+.)*[a-zA-Z0-9-]+.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(/($|[a-zA-Z0-9.,?'\+&%$#=~_-]+))*$/
  return reg.test(url)
}

trim() 方法

const trim1 = (str) => {
  return str.replace(/^\s*|\s*$/g, '') // 或者 str.replace(/^\s*(.*?)\s*$/g, '$1')
}

校验日期格式

//日期
const validDateReg = /^\d{4}([-./])(?:0[1-9]|1[0-2])\1(?:0[1-9]|[12]\d|3[01])$/
//24小时
const validTimeReg = /^(?:(?:0?|1)\d|2[0-3]):(?:0?|[1-5])\d$/

HTML 转义

//防止 XSS 攻击,对HTML进行转义
const escape = (string) => {
  const escapeMaps = {
    '&': 'amp',
    '<': 'lt',
    '>': 'gt',
    '"': 'quot',
    "'": '#39'
  }
  // The effect here is the same as that of /[&amp;<> "']/g
  const escapeRegexp = new RegExp(`[${Object.keys(escapeMaps).join('')}]`, 'g')
  return string.replace(escapeRegexp, (match) => `&${escapeMaps[match]};`)
}

console.log(escape(`
  <div>
    <p>hello world</p>
  </div>
`))
/*
&lt;div&gt;
  &lt;p&gt;hello world&lt;/p&gt;
&lt;/div&gt;
*/

HTML 反转义

const unescape = (string) => {
  const unescapeMaps = {
    'amp': '&',
    'lt': '<',
    'gt': '>',
    'quot': '"',
    '#39': "'"
  }
  const unescapeRegexp = /&([^;]+);/g
  return string.replace(unescapeRegexp, (match, unescapeKey) => {
    return unescapeMaps[ unescapeKey ] || match
  })
}

console.log(unescape(`
  &lt;div&gt;
    &lt;p&gt;hello world&lt;/p&gt;
  &lt;/div&gt;
`))
/*
<div>
  <p>hello world</p>
</div>
*/