才发现一直没有给正则表达式写个博文,今天正好有空来写写。因为JS比较方便测试,打开个网页就可以了,所以下面代码就以JS为基础写。
创建
- 元字符必须转义:
{}[]\^$|()?*+.
- 转义字符:
\
采用字面量创建:var 变量 = /正则表达式/匹配模式
RegExp
该类型支持正则表达式,可以创建一个正则表达式
// 下面两种方法是等价的
// 匹配[bc]at,不区分大小写
var pattern4 = /\[bc\]at/i
var pattern6 = new RegExp("\\[bc\\]at", "i")
模式
- g:表示匹配所有字符串,应用于所有字符串,不会在匹配到第一个时结束
let str = "The rain in Spain stays mainly in the plain";
let regex = /in/g;
let matches = str.match(regex);
console.log(matches); // 输出: [ 'in', 'in', 'in' ]
- i:不区分大小写
// 匹配含有 hello 的字符串
let str = "Hello World";
let regex = /hello/i;
let result = regex.test(str);
console.log(result); // 输出: true
- m:单行匹配匹配
- 一行一行去匹配
- 影响
^
和$
的行为,使它们匹配每一行的开头和结尾,而不仅仅是整个字符串的开头和结尾。
// 匹配开头为 Second 的字符串
let str = "First line\nSecond line";
let regex = /^Second/m;
let result = regex.test(str);
console.log(result); // 输出: true
- s:忽略换行符
- 使
.
可以匹配包括换行符在内的任何字符。
- 使
let str = "Hello\nWorld";
let regex = /Hello.World/s;
let result = regex.test(str);
console.log(result); // 输出: true
规则
这里就不一一演示了,自己试一下就可以,主要看下一章的案例
|
:或的意思,例如检查字符串是否存在a或b,/a|b/
[]
:里的内容也是或的关系,原子表[ab] == a|b
;[a-z]
:任意小写字母;[A-Z]
任意大写字母;[A-z]
任意字母;[0-9]
任意数字
[^]
:除了,例:[^ae]
>不选择a和e字母
()
:优先级
{n}
:出现n次;{m,n}
:出现m到n次;m,
:出现m次以上
+
:至少一个,等价于{1,}
*
:0个或多个,等价于{0,}
?
:0个或1个,等价于{0,1}
,https?
表示s可能会不存在->http
^
:匹配开头,例如检查一个字符串中是否以a开头/^a/
$
:匹配结尾,边界符
.
:除了换行符以外的所有字符
\
:转义,例如如果想表示点号则需要\.
?:
:表示不保留,(?:com|cn)
意为我匹配这段但是不保留
\w
:任意字母、数字、_[A-z0-9_]
\W
:除了字母、数字、_[^A-z0-9_]
\d
:任意的数字[0-9]
\D
:除了数字[^0-9]
\s
:匹配任何空白字符,包括空格、制表符、换页符等等。\S
:匹配任何非空白字符。\b
:单词边界=>单词或非单词之间(意思是,该单词前面或后面不存在内容)看下面例子\B
:除了单词边界例:创建一个正则表达式检查一个字符串中是否含有单词child=>
/\bchild\b/
—>'hello child'
例:去掉开头和结尾空格=>
/^\s*|\s*$/g
匹配任意字符:
(.*?)
字符串方法
string.search()
:搜索指定内容,返回其位置,找不到就-1
let str = "Hello, world!";
let position = str.search(/world/);
console.log(position); // 输出: 7
string.split()
:返回值是一个通过reg切分的数组, 参数二是长度
let str = "apple,banana,cherry";
let array = str.split(/,/);
console.log(array); // 输出: ["apple", "banana", "cherry"]
string.match()
:将符合条件的内容提取出来
let str = "The rain in Spain stays mainly in the plain";
let matches = str.match(/ain/g);
console.log(matches); // 输出: ["ain", "ain", "ain"]
string.replace()
:将字符串中指定内容替换为新的内容,两个参数,替换内容和新内容。
let str = "Hello, world!";
let newStr = str.replace("world", "universe");
console.log(newStr); // 输出: "Hello, universe!"
正则表达式方法
test()
:按规则查找,返回true和false
let regex = /hello/i;
let result = regex.test("Hello, world!");
console.log(result); // 输出: true
exec()
:返回包含第一个匹配项信息的数组,没有匹配项返回null。- 有两个格外属性:index(匹配项在字符串的位置)和input(字符串)
let regex = /h(ell)o/;
let result = regex.exec("Hello, world!");
console.log(result);
// 输出: ["Hello", "ell"]
// result.index: 0
// result.input: "Hello, world!"
- 下面的就有点特殊,他们都是RegExp的函数。你需要先运行1+个的正则表达式匹配方法才能使用下面函数。
lastMatch
:最近一次匹配项lastParen
:最近一次匹配的捕获组leftContext
:字符串中lastMatch之前的文本multiline
:布尔值、是否是多行模式rightContext
:字符串中lastMatch之后的文本
let regex = /(foo)bar/;
let str = "foobar";
regex.test(str); // 或者使用 regex.exec(str);
console.log(RegExp.lastMatch); // 输出: "foobar"
console.log(RegExp.lastParen); // 输出: "foo"
console.log(RegExp.leftContext); // 输出: ""
console.log(RegExp.rightContext); // 输出: ""
console.log(RegExp.multiline); // 输出: false
- 小总结
- test检查指定字符串是否存在
- exec和match都可以获取值,区别一个是正则表达式的方法,一个是字符串的方法
进阶用法
原子组
如果你要获取某个地方的东西,那就给他个()
,例如这样
在 replace中可以通过$2
获取到第二个原子组((\w+)
)的信息
// 我希望获取到标签名以及标签内容
let str = '<h1>123</h1>'
let reg = /<(h[1-6])>(\w+)<\/h1>/
// 将整个标签替换为标签的内容
console.log(str.replace(reg, '$2')) // 123
str.replace(reg, (p0, p1, p2) => {
// p0 = <h1>123</h1>
// p1 = h1
// p2 = 123
console.log(p0, p1, p2)
})
console.log(str.match(reg)[2]) // 123
$&
: 代表自己
let str = '<a href=<123>456>789>'
main.innerHTML.replace(/替换/g. `<a href="#">已被$&</a>`)
// 页面会显示为:已被替换
- 忽略原子组:
?:
let str = '<h1>123</h1>'
let reg = /<(?:h[1-6])>(\w+)<\/h1>/
console.log(str.match(reg)[1]) // 123
断言匹配
断言简单来说就是根据条件筛选出特点的符合条件的内容
?= /条件(?=内容)/ // 匹配出后面具有某内容的条件
?<= /(?<=内容)条件/ // 匹配出前面具有某内容的条件
?! /条件(?!内容)/ // 匹配出后面不具有某内容的条件
?<! /(?<!内容)条件/ // 匹配出前面不具有某内容的条件
?=
: 匹配出后面具有某内容的条件
let str = "你知道么555啦啦啦";
const reg = /\d+(?=啦)/;
console.log(reg.exec(str)); // 555
?<=
: 匹配出前面具有某内容的条件
// 前面第一个字是关键字 "么" ,那么返回这段数字
let str = "你知道么555啦啦啦";
const reg = /(?<=么)\d+/;
console.log(reg.exec(str)); // 555
其他
- 禁止贪婪
?
- 第一次匹配成功,就不再往后匹配了
let str = '<a href=<123>456>789>'
console.log(str.match(/<a href=<(.*)>/)) // 123>456>789
console.log(str.match(/<a href=<(.*?)>/)) // 123
- 命名捕获
?<关键字>
,使用$<关键字>
捕获
const reg = /<h1>(?<text>.*)<\/h2>/
let str = '<h1>baidu</h1>'
console.log(str.replace(reg, '<h2>$<text></h2>')) // <h1>baidu</h1>
案例
- 限定用户名输入的长度只能是6-10位字母,数字,下划线
// 限定用户名输入的长度只能是6-10位字母,数字,下划线
let reg = /^[a-z0-9_]{6,10}$/i
- 驼峰格式替换
// 驼峰格式替换
let str = "get-element-by-id";
let reg = /-\w/g;
str = str.replace(reg, (res) => {
return res[1].toUpperCase();
});
console.log(str); // getElementById
- 满足xxxx-xx-xx或者xxxx/xx/xx的都符合日期格式要求
// 满足xxxx-xx-xx或者xxxx/xx/xx的都符合日期格式要求
let date1 = "2021/04/01"
let date2 = "2021-04-01"
let reg = /^\d{4}([-/])\d{2}\1\d{2}$/
console.log(reg.test(date1)); // true
console.log(reg.test(date2)); // true
- 对下面三个链接进行替换,把不是https的替换成https,没有www的添加www
// 对下面三个链接进行替换,把不是https的替换成https,没有www的添加www
let a1 = "http://www.baidu.com"
let a2 = "http://www.taobao.com"
let a3 = "https://jd.com"
let arr = [a1, a2, a3]
let reg = /(https?)(:\/\/)(www.)?(.*)/ig
let res = arr.map(item => {
return item.replace(reg, (...args) => {
args[1] = args[1] === "http" ? "https" : args[1]
args[3] = args[3] || "www."
return args.splice(1,4).join("")
})
})
console.log(res) // ["https://www.baidu.com", "https://www.taobao.com", "https://www.jd.com"]
- 把下面的h1,h2标签替换成p标签
// 把下面的h1,h2标签替换成p标签
let dom = `
<h1>ychizzz</h1>
<span>chizzz</span>
<h2>YCHIZZZ</h2>
`
let reg = /<(h[1-6])>([\s\S]+)<\/\1>/ig
// 此处的args从第1项开始代表了每个组,因为正则里表示内容的组([\s\S])是第二个,因此取args[2]
dom.replace(reg, (...args) => `<p>args[2]</p>`)
- 密码验证,大小写字母
input.addEventListener('keyup', e => {
const value = e.target.value
let r = [/^[a-z]{5,10}$/i, /[A-Z]/, /[0-9]]/]
let state = r.every(e => e.test(value))
console.log(state ? 'yes' : 'no')
})
- 只获取中文
let str = '你好世界! Hello World 你好'
let reg = /[^\w\!\s]+/g
let reg2 = /\p{sc=Han}+/gu
console.log(str.match(reg2)) // [ '你好世界', '你好' ]