在上篇 JS 使用正则表达式的方式 文章中我们学习了如何用正则表达式,这篇文章介绍一下如何学习正则表达式。
正则表达式比较抽象,对于初学者并不友好,起初我看了《精通正则表达式》这本书,仅看了一部分。主要在工作中没遇到比较难的正则表达式,如果有这方面需求可以深入学习。
如果你想要这本电子书,可以私信我。
正则表达式本质上是一个文本处理工具,可以对文本进行增、删、改、查操作,它比字符串提供的方法更灵活,有时候你写几十行代码用正则几行即可搞定,这时别人会给你个大拇指。比如,把一个字符串后面的 0 去掉,如果不用正则,你会如何做?
0.0100 // 0.01
0.01 // 0.01
1.00 // 1
100. // 100
100; // 100
通过正则实现:
const removeEndZero = text => {
if (/\./.test(text)) {
text = text.replace(/0+$/, '');
text = text.replace(/\.$/, '');
}
return text;
}
正则表达式没有标准答案,同一类问题会有多种表示方法,只要能满足自己的业务需求即可,尽可能的考虑多种异常情况。它的工作方式就是从满足正则条件的子字符串,而正则中定义了字符长什么样。
正则举例
1、匹配开头结尾,正则会从头或尾匹配符合条件的字符串:
const useStartEnd = () => {
let text = 'suyan 12 age suyan, n_name';
// 要匹配的字符串必须以 s 开头
// suyan
let ret = text.match(/^s\w+/g);
console.log('ret = ', ret);
// 要匹配的字符串必须以 e 结尾
ret = text.match(/\w+e$/g);
// n_name
console.log('ret = ', ret);
}
2、匹配某些特定的字符
const useCharGroup = () => {
// 匹配 suyan,s不分大小写
// [] 匹配一组可能出现的字符
const text = 'Suyan is a suyan';
const reg = /[Ss]uyan/g;
let ret = text.match(reg);
// [ 'Suyan', 'suyan' ]
console.log('ret = ', ret);
// 区间可表示多个字符
const text2 = '$s.1e4G';
// 匹配所有的数字、大小写字母
// 如果要匹配特殊字符,使用 \ 即可
const reg2 = /[a-zA-Z0-9]/g;
ret = text2.match(reg2);
// [ 's', '1', 'e', '4', 'G' ]
console.log('ret = ', ret);
const text3 = 'suyan';
// ^ 取反,不能包含 sy
// [ 'u', 'a', 'n' ]
ret = text3.match(/[^sy]/g)
console.log('ret = ', ret);
}
3、巧用缩写,简化正则
一些特定的字符可以表示一个字符集,无需把每个字符一一列出。
const useQuickKey = () => {
let text = 'suyan 12 age, n_name';
// \w 表示 [a-zA-Z0-9_],取反 \W
let ret = text.match(/\w/g);
// \s 匹配空白字符,空格、换行、tab
ret = text.match(/\s/g);
// \b 单词边界、分割成单词
ret = text.split(/\b/g);
console.log('ret = ', ret);
};
4、使用 . 匹配除\n
, \r
, \u2028
or \u2029
外的任意字符
const useAnyChar = () => {
let text = 'n_name';
// . 匹配任意字符,除了不能匹配 \n
let ret = text.match(/n.../g);
console.log('ret = ', ret);
}
5、使用 ?,可选,表示 0 个或 1 个
const useKeXuanChar = () => {
let text = 'Suyan is Suuyan';
// ? 可选字符,匹配 0 个或 1 个
// Suyan Suuyan
let ret = text.match(/Suu?yan/g);
console.log('ret = ', ret);
}
6、使用 {m, n},表示任意个,+ 表示 1 个或多个
const useMoreChar = () => {
let text = '010-89283 0101-8899';
// {3} 重复3次,即3个字符
let ret = text.match(/\d{3}-\d{4}/g);
// {3,4} 重复 3到4次
ret = text.match(/\d{3,4}-\d{4}/g);
// {1,} 1到任意多个,可用+表示
// {0,} 0到任意多个,可用 * 表示
console.log('ret = ', ret);
}
7、使用捕获组
const useGroup = () => {
const text = 'image size is 300x500';
let reg = /(\d+)x(\d+)/;
let ret = text.match(reg);
/** 匹配结果中包含了组
* ret = [
'300x500',
'300',
'500',
index: 14,
input: 'image size is 300x500',
groups: undefined
]
*/
console.log('ret = ', ret);
}
8、使用非捕获组
const useNotGroup = () => {
const text = 'image size is 300x500';
// (?:x)匹配 x,但是结果中不包含 x
let reg = /(\d+)x(?:\d+)/;
let ret = text.match(reg);
/** 匹配结果中包含了组
* ret = [
'300x500',
'300',
index: 14,
input: 'image size is 300x500',
groups: undefined
]
*/
console.log('ret = ', ret);
}
9、使用具名捕获组
const useNameGroup = () => {
const text = 'image size is 300x500';
// (?:x)匹配 x,并给组设置名字
let reg = /(?\d+)x(?\d+)/;
let ret = text.match(reg);
/** 匹配结果中包含了组
ret = [
'300x500',
'300',
'500',
index: 14,
input: 'image size is 300x500',
groups: [Object: null prototype] { width: '300', height: '500' }
]
*/
console.log('ret = ', ret.groups.width);
console.log('ret = ', ret.groups.height);
}
最后送大家一张表:
^
: 从字符串开始位置匹配,^lefe:以 lefe 开头的文本;
$
: 从字符串的结尾匹配,$lefe:以 lefe 结尾的文本;
*
: 匹配0个或多个字符,lefe*:lef 后出现0个或多个e,lef,lefeeee 合法;
+
: 匹配1个或多个字符,lefe+:lef 后出现1个或多个e,lefe,lefeeee 合法;
?
: 匹配0个或者1个字符,lefe?:lef 后出现0个或1个e,lef,lefe 合法;
{m}
: 匹配 m 次,lefe{2}: lefe 后出现 1 个 e,lefee 合法;
{m,}
: 匹配至少 m 次,lefe{2,}: lefe 后至少出现 1 个 e,lefee,lefeee 合法;
{m,n}
: 匹配 m dao n 次,lefe{2,3}: lefe 后出现 1 个 或者 2 个 e,lefee,lefeee 合法;
\d
: 匹配任意0-9的数字,比如:123,23;
\D
: 与 \d 相反,匹配不是0-9的字符,比如:lefe;
\w
: 匹配任何数字和字母,还有下划线,比如:lefe_x;
\W
: 与 \w 相反;
\s
: 匹配任何空格字符,与 [\n\t\r\f] 相同;
\S
: 与 \s 相反;
\b
: 匹配单词边界,比如使用正则表达式'\w*\b' 匹配 'lefe_x is wsy',将匹配到 lefe_x,is 和 wsy;
\B
: 与 \b 相反;
[字符]
: 匹配[]中的任意单个字符,比如[lefx] 匹配 l,e,f 和 x 中的任意一个字符;
[^字符]
: 匹配除[]中的任意单个字符,比如[lefx] 匹配除了 l,e,f 和 x 的任意字符;
[a-z]
: 匹配 a 到 z 任意字母;
A|B|C
: 只能匹配 A,B 和 C 的任意一个,lefe|lefe_x|wsy 匹配 lefe 或 lefe_x 或 wsy;
.
: 匹配除 \n, \r, \u2028 or \u2029 任何单个字符;
()
: 分组,可以获取分组中的内容,比如:'\[UIImage imageNamed:@"(.+?)"'
,匹配 [UIImage imageNamed:@"lefe"]
可以从匹配结果中获取到图片的名字 lefe;
\数字
:引用分组,比如:^<([a-z]+)>.*<\/\1>' 可以匹配
hello lefe`
(?:)
: 非获取匹配,在匹配结果中将忽略这个分组;
(?=)
: 非获取匹配,正向肯定预查,正则表达式'window(?=98|95|2000)'
可以匹配 window98
或 window95
或 window2000
中的 window
;
(?!)
: 非获取匹配,正向否定预查,正则表达式'window(?!98|95|2000)'
可以匹配window2007
中的 window
, 不可以匹配 window98
或 window95
或 window2000
中的 window
;
(?<=)
: 非获取匹配,反向肯定预查,正则表达式'(?<=98|95|2000)window'
可以匹配 98window
或 95window
或 2000window
中的 window
;
(?: 非获取匹配,反向否定预查,正则表达式
'(? 可以匹配
2007window
中的 window
, 不可以匹配 98window
或 95window
或 2000window
中的 window
;
大家加油。前端所有的 demo 都在这里:
https://github.com/lefex/FE
长按关注
素燕《前端小课》
帮助 10W 人入门并进阶前端
官网:https://lefex.gitee.io/