正则表达式的创建和使用
创建正则表达式的两种方式
01 使用正则表达式字面量
const reg = /[a-z]\d+[a-z]/i;
优点
- 简单方便
- 不需要考虑二次转义
缺点
- 子内容无法重复使用
- 过长的正则导致可读性差
02 使用 RegExp 构造函数
const alphabet = '[a-z]';
const reg = new RegExp(`${alphabet}\\d+${alphabet}`, 'i');
优点
- 子内容可以重复使用
- 可以通过控制子内容的粒度提高可读性
缺点
- 二次转义的问题非常容易导致 bug
const reg = new RegExp(`\d+`);
reg.test('1'); // false
reg.test('ddd'); // true
正则表达式的常见用法
01 RegExp.prototype.test()
const reg = /[a-z]\d+[a-z]/i;
reg.test('a1a'); // true
reg.test('1a1'); // false
reg.test(Symbol('a1a')); // TypeError
输入
要求输入字符串,如果输入的不是字符串类型,会尝试进行类型转换,转换失败会抛出 TypeError
输出
true 或者 false,表示匹配成功或失败
02 RegExp.prototype.source 和 RegExp.prototype.flags
const reg = /[a-z]\d+[a-z]/ig;
reg.source; // "[a-z]\d+[a-z]"
reg.flags; // "gi"
get RegExp.prototype.source
返回当前正则表达式的模式文本的字符串
get RegExp.prototype.flags
es2015新增,返回当前正则表达式的修饰符的字符串,会对修饰符按照字母升序进行排序(gimsuy)
03 RegExp.prototype.exec() 和 String.prototype.match()
输入
RegExp.prototype.exec 要求输入字符串,遇到非字符串类型会尝试转换
String.prototype.match 要求输入正则表达式,遇到其它类型会先尝试转成字符串,再以字符串为 source 创建正则表达式
输出
匹配成功,返回匹配结果
匹配失败,返回 null
const reg = /(a)/g;
reg.exec('a1a'); // ["a", "a", index: 0, input: "a1a", groups: undefined]
'a1a'.match(reg); // ["a", "a"]
当正则表达式含有 g 修饰符时,RegExp.prototype.exec 每次只返回一个匹配结果,数据格式和不含 g 修饰符相同。
String.prototype.match 会返回所有的匹配结果,数据格式会变为字符串数组。
由于 String.prototype.match 返回的数据格式不固定,因此大多数情况都建议使用 RegExp.prototype.exec
04 RegExp.prototype.lastIndex
const reg = /(a)/g;
const str = 'a1a';
reg.lastIndex; // 0
reg.exec('a1a'); // ["a", "a", index: 0, input: "a1a", groups: undefined]
reg.lastIndex; // 1
reg.exec('a1a'); // ["a", "a", index: 2, input: "a1a", groups: undefined]
reg.lastIndex; // 3
reg.exec('a1a'); // null
reg.lastIndex; // 0
当前正则表达式最后一次匹配成功的结束位置(也就是下一次匹配的开始位置)
注意:lastIndex 不会自己重置,只有当上一次匹配失败才会重置为 0 ,因此,当你需要反复使用同一个正则表达式的时候,请在每次匹配新的字符串之前重置 lastIndex!
05 String.prototype.replace()、String.prototype.search()、String.prototype.split()
'a1a'.replace(/a/, 'b'); // 'b1a'
'a1a'.replace(/a/g, 'b'); // 'b1b'
'a1a'.search(/a/); // 0
'a1a'.search(/a/g); // 0
'a1a'.split(/a/); // ["", "1", ""]
'a1a'.split(/a/g); // ["", "1", ""]
场景一:正则与数值
数值判断不简单
01 /[0-9]+/
[]
字符集,使用连字符 - 表示指定的字符范围,如果想要匹配连字符,需要挨着方括号放置,或进行转义
0-9 表示匹配从 0 到 9 的数字字符,常用的还有 a-z 匹配小写字母,\u4e00-\u9fa5 匹配汉字等
如果只是匹配数字,还可以使用字符集缩写 \d
+
限定符,匹配一个或多个
这个正则的缺点
不是全字符匹配,存在误判,如 /[0-9]+/.test('a1') === true
02 /^\d+$/
^
匹配字符串开始位置,当结合 m 修饰符时,匹配某一行开始位置
$
匹配字符串结束位置,当结合 m 修饰符时,匹配某一行结束位置
这个正则的缺点
不能匹配带符号的数值,如 +1,-2
不能匹配小数,如 3.14159
03 /^[+-]?\d+(\.\d+)?$/
()
圆括号内是一个子表达式,当圆括号不带任何修饰符时,表示同时创建一个捕获组
?
? 在正则中有多种含义,作为限定符时,表示匹配零到一个
\.
. 可以匹配除换行符之外的任意字符,当结合 s 修饰符时,可以匹配包括换行符在内的任意字符
当匹配小数点字符时需要转义
这个正则的缺点
不能匹配无整数部分的小数,如 .123
捕获组会带来额外的开销
04 /^[+-]?(?:\d*\.)?\d+$/
(?:)
(?:)意思
这个代表不捕获分组
比较(X)和(?:X),前者是捕获分组,后者不捕获,区别在于正则表达式匹配输入字符串之后所获得的匹配的(数)组当中没有(?:X)匹配的部分;
比如
var m = "abcabc".match(/(?:a)(b)(c)/)
//结果 ["abc", "b", "c"]
// m[0] 是/(?:a)(b)(c)/匹配到的整个字符串,这里包括了a
// m[1] 是捕获组1,即(b)匹配的子字符串substring or sub sequence
// m[2] 是捕获组2,即(c)匹配到的
如果这样
var m = "abcabc".match(/(a)(b)(c)/)
//结果 ["abc", "a", "b", "c"]
创建一个非捕获组
可参考 https://www.cnblogs.com/pmars/archive/2011/12/30/2307507.html
(捕获组的编号是按照“(”出现的顺序,从左到右,从1开始进行编号的。)
*
限定符,匹配零个或多个
这个正则的缺点
不能匹配无小数部分的数值,如 2.
不能匹配科学计数法,如 1e2、3e-1、-2.e+4
完整的数值正则怎么写?
01 完整的数值 token
https://drafts.csswg.org/css-syntax-3/#number-token-diagram
注意:这个 token 是 CSS 的 token,在 javascript 中,要多考虑一种情况
+'2.'; // 2
+'2.e1'; // 20
02 /^[+-]?(?:\d+\.?|\d*\.\d+)(?: e[+-]?\d+)?$/i
|
javascript 中,数值还可以如何表示?
答案稍后给出
用来创建分支,当位于圆括号内时,表示子表达式的分支条件,当位于圆括号外时,表示整个正则表达式的分支条件
i 修饰符
思考题:这个正则已经没有缺点了吗?
表示匹配时忽略大小写,在这个例子中用于匹配科学计数法的 e,去掉 i 修饰符需要把 e 改为 [eE]
用正则处理数值
01 数值的解析
function execNumberList(str) {
// ……
}
console.log(execNumberList('1.0px .2px -3px +4e1px')); // [1, 0.2, -3, 40]
console.log(execNumberList('+1.0px -0.2px 3e-1px')); // [1, -0.2, 0.3]
console.log(execNumberList('1px 0')); // [1, 0]
console.log(execNumberList('-1e+1px')); // [-10]
const reg = /[+-]?(?:\d*\.)?\d+(?:e[+-]?\d+)?(?=px|\s|$)/gi;
function execNumberList(str) {
reg.lastIndex = 0;
let exec = reg.exec(str);
const result = [];
while (exec) {
result.push(parseFloat(exec[0]));
exec = reg.exec(str);
}
return result;
}
console.log(execNumberList('1.0px .2px -3px +4e1px')); // [1, 0.2, -3, 40]
console.log(execNumberList('+1.0px -0.2px 3e-1px')); // [1, -0.2, 0.3]
console.log(execNumberList('1px 0')); // [1, 0]
console.log(execNumberList('-1e+1px')); // [-10]
const reg = /[+-]?(?:\d*\.)?\d+(?:e[+-]?\d+)?(?=px|\s|$)/gi;
(?=expression)
正向肯定环视 / 顺序肯定环视 / 先行断言
用于匹配符合条件的位置
类似的语法还有:
(?!expression) 正向否定环视 / 顺序否定环视 / 先行否定断言
(?<=expression) 反向肯定环视 / 逆序肯定环视 / 后行断言,es2018 新增
(?<!expression) 反向否定环视 / 逆序否定环视 / 后行否定断言,es2018 新增
const reg = /[+-]?(?:\d*\.)?\d+(?:e[+-]?\d+)?(?=px|\s|$)/gi;
g
修饰符,表示全局匹配,用于取出目标字符串中所有符合条件的结果
需要注意的点
- 按照 CSS 规范,只有数值为 0 才可以省略单位,这种情况没有必要靠正则来过滤
- 这个例子中只验证了 px 单位,实际还存在 pt、em、vw 等单位,并且没有考虑百分比的情况
- 实际工作中,要根据需求追加处理逻辑
02 数值转货币格式
function formatCurrency(str) {
// ……
}
console.log(formatCurrency('1')); // 1
console.log(formatCurrency('123')); // 123
console.log(formatCurrency('12345678')); // 12,345,678
const reg = /(\d)(?=(\d{3})+(,|$))/g;
function formatCurrency(str) {
return str.replace(reg, '$1,');
}
console.log(formatCurrency('1')); // 1
console.log(formatCurrency('123')); // 123
console.log(formatCurrency('12345678')); // 12,345,678
{n}
限定符,表示重复 n 次,n 必须是非负整数
类似的语法还有:
{n, m} 表示重复 n 到 m 次,n 和 m 都必须是非负整数,且 n <= m
{n,} 表示重复 n 次以上
$n
用于 replace 的字符串中,表示第 n 个捕获组,n 可以从 1 到 9
$& 表示本次完整的匹配,所以这段代码还可以改写为:
const reg = /\d(?=(?:\d{3})+(?:,|$))/g;
function formatCurrency(str) {
return str.replace(reg, '$&,');
}
在 es2018 以上的环境,还可以使用反向环视
const reg = /(?<=\d)(?=(?:\d{3})+(?:,|$))/g;
function formatCurrency(str) {
return str.replace(reg, ',');
}
其它注意事项
环视中的圆括号也会生成捕获组,所以都要采用 (?:) 的非捕获组形式
颜色有多少种表示方式
01 16进制表示法
color: #rrggbb;
color: #rgb;
color: #rrggbbaa;
color: #rgba;
对应的正则写法
const hex = '[0-9a-fA-F]';
const reg = new RegExp(`^(?:#${hex}{6}|#${hex}{8}|#${hex}{3,4})$`);
其它注意事项
- 也可以使用 i 修饰符来匹配大小写,i 修饰符和 a-fA-F 要根据实际需求来做取舍
- 还记得前面的问题吗?
02 rgb/rgba 表示法
color: rgb(r, g, b);
color: rgb(r%, g%, b%);
color: rgba(r, g, b, a);
color: rgba(r%, g%, b%, a);
color: rgba(r, g, b, a%);
color: rgba(r%, g%, b%, a%);
对应的正则写法
const num = '[+-]?(?:\\d*\\.)?\\d+(?:e[+-]?\\d+)?';
const comma = '\\s*,\\s*';
const reg = new RegExp(`rgba?\\(\\s*${num}(%?)(?:${comma}${num}\\1){2}(?:${comma}${num}%?)?\\s*\\)`);
\n
反向引用,表示引用第 n 个捕获组
由于 r/g/b 必须同时为数值或百分比,所以 %? 只需要捕获一次,用 \1 来引用
\s
字符集缩写,用于匹配空白
需要注意的点
- 按照规范,rgb(r,g,b,a) 和 rgba(r,g,b) 也是合法的
- r/g/b 的值应该是 0~255 的整数,但是溢出或小数并不会报错
- 当捕获组内的内容是可选的时候,一定要把问号写在捕获组内
如果可选内容的圆括号不可省略,如(a|b|c)?,应该多嵌套一层:((?:a|b|c)?)
03 其它
/* hsl & hsla */
color: hsl(h, s%, l%);
color: hsla(h, s%, l%, a);
color: hsla(h, s%, l%, a%);
/* keywords */
color: red;
color: blue;
/* …… */
更多的颜色表示方法:
https://www.w3.org/TR/css-color/
用正则处理颜色
01 16进制颜色的优化
function shortenColor(str) {
// ……
}
console.log(shortenColor('#336600')); // '#360'
console.log(shortenColor('#19b955')); // '#19b955'
console.log(shortenColor('#33660000')); // '#3600'
const hex = '[0-9a-z]';
const hexReg = new RegExp(`^#(?<r>${hex})\\k<r>(?<g>${hex})\\k<g>(?<b>${hex})\\k<b>(?<a>${hex}?)\\k<a>$`, 'i');
function shortenColor(str) {
return str.replace(hexReg, '#$<r>$<g>$<b>$<a>');
}
console.log(shortenColor('#336600')); // '#360'
console.log(shortenColor('#19b955')); // '#19b955'
console.log(shortenColor('#33660000')); // '#3600'
(?<key>)
- es2018 新增,具名捕获组
- 反向引用时的语法为 \k<key>
- 在 replace 中,使用 $<key> 来访问具名捕获组
- 当应用 exec 时,具名捕获组可以通过 execResult.groups[key] 访问
const hex = '[0-9a-z]';
const hexReg = new RegExp(`^#(?<r>${hex})\\k<r>(?<g>${hex})\\k<g>(?<b>${hex})\\k<b>(?<a>${hex}?)\\k<a>$`, 'i');
hexReg.exec('#33660000');
// ["#33660000", "3", "6", "0", "0", index: 0, input: "#33660000", groups: {r: "3", g: "6", b: "0", a: "0"}]
场景三:正则与URL
01 用正则解析 URL
https://www.rfc-editor.org/rfc/rfc3986.html#section-3
简单起见,scheme 我们只匹配 http 和 https ,忽略 userinfo 部分
02 解析 URL
function execURL(url) {
// ……
}
console.log(execURL('https://www.360.cn'));
{
protocol: 'http:',
host: 'www.360.cn',
hostname: 'www.360.cn',
port: '',
pathname: '',
search: '',
hash: ''
}
console.log(execURL('http://localhost:8080/?#'));
{
protocol: 'http:',
host: 'localhost:8080',
hostname: 'localhost',
port: '8080',
pathname: '/',
search: '?',
hash: '#'
}
console.log(execURL('https://image.so.com/view?q=360&src=srp#id=9e17bd&sn=0'));
{
protocol: 'https:',
host: 'image.so.com',
hostname: 'image.so.com',
port: '',
pathname: '/view',
search: '?q=360&src=srp',
hash: '#id=9e17bd&sn=0'
}
console.log(execURL('this is not a url'));
{
protocol: '',
host: '',
hostname: '',
port: '',
pathname: '',
search: '',
hash: ''
}
const protocol = '(?<protocol>https?:)';
const host = '(?<host>(?<hostname>[^/#?:]+)(?::(?<port>\\d+))?)';
const path = '(?<pathname>(?:\\/[^/#?]+)*\\/?)';
const search = '(?<search>(?:\\?[^#]*)?)';
const hash = '(?<hash>(?:#.*)?)';
const reg = new RegExp(`^${protocol}\/\/${host}${path}${search}${hash}$`);
function execURL(url) {
const result = reg.exec(url);
if (result) {
result.groups.port = result.groups.port || '';
return result.groups;
}
return {
protocol: '', host: '', hostname: '', port: '',
pathname: '', search: '', hash: '',
};
}
console.log(execURL('https://www.360.cn'));
console.log(execURL('http://localhost:8080/?#'));
console.log(execURL('https://image.so.com/view?q=360&src=srp#id=9e17bd&sn=0'));
console.log(execURL('this is not a url'));
注意事项
- port 捕获组可能为 undefined
- 要考虑解析失败的情形
用正则解析 search 和 hash
完整解析
function execUrlParams(str) {
// ……
}
console.log(execUrlParams('#')); // { }
console.log(execUrlParams('##')); // { '#': '' }
console.log(execUrlParams('?q=360&src=srp')); // { q: '360', src: 'srp' }
console.log(execUrlParams('test=a=b=c&&==&a=')); // { test: 'a=b=c', '': '=', a: '' }
function execUrlParams(str) {
str = str.replace(/^[#?&]/, '');
const result = {};
if (!str) {
return result;
}
const reg = /(?:^|&)([^&=]*)=?([^&]*?)(?=&|$)/y;
let exec = reg.exec(str);
while (exec) {
result[exec[1]] = exec[2];
exec = reg.exec(str);
}
return result;
}
console.log(execUrlParams('#')); // { }
console.log(execUrlParams('##')); // { '#': '' }
console.log(execUrlParams('?q=360&src=srp')); // { q: '360', src: 'srp' }
console.log(execUrlParams('test=a=b=c&&==&a=')); // { test: 'a=b=c', '': '=', a: '' }
const reg = /(?:^|&)([^&=]*)=?([^&]*?)(?=&|$)/y;
*?
? 可以跟在任何限定符之后,表示非贪婪模式(注意:这个例子其实不太恰当,使用贪婪模式效果是一样的)
y
es6 新增,粘连修饰符,和 g 修饰符类似,也是全局匹配。区别在于:
- y 修饰符每次匹配的结果必须是连续的
- y 修饰符在 match 时只会返回第一个匹配结果
if (!str) {
return result;
}
02 解析指定 key
这是一道课后作业题,交给大家自己来完成
function getUrlParam(str, key) {
// ……
}
console.log(getUrlParam('?nothing', 'test')); // ''
console.log(getUrlParam('#a=1&aa=2&aaa=3', 'a')); // '1'
console.log(getUrlParam('&b=1&a=1&b=2', 'b')); // '2'
console.log(getUrlParam('a=1&b=2&c=&d', 'c')); // ''
console.log(getUrlParam('&d==', 'd')); // '='
注意事项
- 存在多个重复的 key 时,要求只返回最后一条匹配的结果
- 挑战1:解法不止一种,你可以写出尽可能多的解法吗?
- 挑战2:可以写出尽可能短的正则表达式吗?
总结
怎样用好正则表达式?
- 明确需求
- 考虑全面
- 反复测试
表达式全集
字符 | 描述 |
---|---|
\ | 将下一个字符标记为一个特殊字符、或一个原义字符、或一个向后引用、或一个八进制转义符。例如,“n ”匹配字符“n ”。“\n ”匹配一个换行符。串行“\\ ”匹配“\ ”而“\( ”则匹配“( ”。 |
^ | 匹配输入字符串的开始位置。如果设置了RegExp对象的Multiline属性,^也匹配“\n ”或“\r ”之后的位置。 |
$ | 匹配输入字符串的结束位置。如果设置了RegExp对象的Multiline属性,$也匹配“\n ”或“\r ”之前的位置。 |
* | 匹配前面的子表达式零次或多次。例如,zo*能匹配“z ”以及“zoo ”。*等价于{0,}。 |
+ | 匹配前面的子表达式一次或多次。例如,“zo+ ”能匹配“zo ”以及“zoo ”,但不能匹配“z ”。+等价于{1,}。 |
? | 匹配前面的子表达式零次或一次。例如,“do(es)? ”可以匹配“does ”或“does ”中的“do ”。?等价于{0,1}。 |
{n} | n是一个非负整数。匹配确定的n次。例如,“o{2} ”不能匹配“Bob ”中的“o ”,但是能匹配“food ”中的两个o。 |
{n,} | n是一个非负整数。至少匹配n次。例如,“o{2,} ”不能匹配“Bob ”中的“o ”,但能匹配“foooood ”中的所有o。“o{1,} ”等价于“o+ ”。“o{0,} ”则等价于“o* ”。 |
{n,m} | m和n均为非负整数,其中n<=m。最少匹配n次且最多匹配m次。例如,“o{1,3} ”将匹配“fooooood ”中的前三个o。“o{0,1} ”等价于“o? ”。请注意在逗号和两个数之间不能有空格。 |
? | 当该字符紧跟在任何一个其他限制符(*,+,?,{n},{n,},{n,m})后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串“oooo ”,“o+? ”将匹配单个“o ”,而“o+ ”将匹配所有“o ”。 |
. | 匹配除“\ n ”之外的任何单个字符。要匹配包括“\ n ”在内的任何字符,请使用像“(.|\n) ”的模式。 |
(pattern) | 匹配pattern并获取这一匹配。所获取的匹配可以从产生的Matches集合得到,在VBScript中使用SubMatches集合,在JScript中则使用$0…$9属性。要匹配圆括号字符,请使用“\( ”或“\) ”。 |
(?:pattern) | 匹配pattern但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用或字符“(|) ”来组合一个模式的各个部分是很有用。例如“industr(?:y|ies) ”就是一个比“industry|industries ”更简略的表达式。 |
(?=pattern) | 正向肯定预查,在任何匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,“Windows(?=95|98|NT|2000) ”能匹配“Windows2000 ”中的“Windows ”,但不能匹配“Windows3.1 ”中的“Windows ”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。 |
(?!pattern) | 正向否定预查,在任何不匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如“Windows(?!95|98|NT|2000) ”能匹配“Windows3.1 ”中的“Windows ”,但不能匹配“Windows2000 ”中的“Windows ”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始 |
(?<=pattern) | 反向肯定预查,与正向肯定预查类拟,只是方向相反。例如,“(?<=95|98|NT|2000)Windows ”能匹配“2000Windows ”中的“Windows ”,但不能匹配“3.1Windows ”中的“Windows ”。 |
(?<!pattern) | 反向否定预查,与正向否定预查类拟,只是方向相反。例如“(?<!95|98|NT|2000)Windows ”能匹配“3.1Windows ”中的“Windows ”,但不能匹配“2000Windows ”中的“Windows ”。 |
x|y | 匹配x或y。例如,“z|food ”能匹配“z ”或“food ”。“(z|f)ood ”则匹配“zood ”或“food ”。 |
[xyz] | 字符集合。匹配所包含的任意一个字符。例如,“[abc] ”可以匹配“plain ”中的“a ”。 |
[^xyz] | 负值字符集合。匹配未包含的任意字符。例如,“[^abc] ”可以匹配“plain ”中的“p ”。 |
[a-z] | 字符范围。匹配指定范围内的任意字符。例如,“[a-z] ”可以匹配“a ”到“z ”范围内的任意小写字母字符。 |
[^a-z] | 负值字符范围。匹配任何不在指定范围内的任意字符。例如,“[^a-z] ”可以匹配任何不在“a ”到“z ”范围内的任意字符。 |
\b | 匹配一个单词边界,也就是指单词和空格间的位置。例如,“er\b ”可以匹配“never ”中的“er ”,但不能匹配“verb ”中的“er ”。 |
\B | 匹配非单词边界。“er\B ”能匹配“verb ”中的“er ”,但不能匹配“never ”中的“er ”。 |
\cx | 匹配由x指明的控制字符。例如,\cM匹配一个Control-M或回车符。x的值必须为A-Z或a-z之一。否则,将c视为一个原义的“c ”字符。 |
\d | 匹配一个数字字符。等价于[0-9]。 |
\D | 匹配一个非数字字符。等价于[^0-9]。 |
\f | 匹配一个换页符。等价于\x0c和\cL。 |
\n | 匹配一个换行符。等价于\x0a和\cJ。 |
\r | 匹配一个回车符。等价于\x0d和\cM。 |
\s | 匹配任何空白字符,包括空格、制表符、换页符等等。等价于[ \f\n\r\t\v]。 |
\S | 匹配任何非空白字符。等价于[^ \f\n\r\t\v]。 |
\t | 匹配一个制表符。等价于\x09和\cI。 |
\v | 匹配一个垂直制表符。等价于\x0b和\cK。 |
\w | 匹配包括下划线的任何单词字符。等价于“[A-Za-z0-9_] ”。 |
\W | 匹配任何非单词字符。等价于“[^A-Za-z0-9_] ”。 |
\xn | 匹配n,其中n为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如,“\x41 ”匹配“A ”。“\x041 ”则等价于“\x04&1 ”。正则表达式中可以使用ASCII编码。. |
\num | 匹配num,其中num是一个正整数。对所获取的匹配的引用。例如,“(.)\1 ”匹配两个连续的相同字符。 |
\n | 标识一个八进制转义值或一个向后引用。如果\n之前至少n个获取的子表达式,则n为向后引用。否则,如果n为八进制数字(0-7),则n为一个八进制转义值。 |
\nm | 标识一个八进制转义值或一个向后引用。如果\nm之前至少有nm个获得子表达式,则nm为向后引用。如果\nm之前至少有n个获取,则n为一个后跟文字m的向后引用。如果前面的条件都不满足,若n和m均为八进制数字(0-7),则\nm将匹配八进制转义值nm。 |
\nml | 如果n为八进制数字(0-3),且m和l均为八进制数字(0-7),则匹配八进制转义值nml。 |
\un | 匹配n,其中n是一个用四个十六进制数字表示的Unicode字符。例如,\u00A9匹配版权符号(©)。 |
常用正则表达式
用户名 | /^[a-z0-9_-]{3,16}$/ |
---|---|
密码 | /^[a-z0-9_-]{6,18}$/ |
十六进制值 | /^#?([a-f0-9]{6}|[a-f0-9]{3})$/ |
电子邮箱 | /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/ /^[a-z\d]+(\.[a-z\d]+)*@([\da-z](-[\da-z])?)+(\.{1,2}[a-z]+)+$/ |
URL | /^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/ |
IP 地址 | /((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)/ /^(?:(?: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]?)$/ |
HTML 标签 | /^<([a-z]+)([^<]+)*(?:>(.*)<\/\1>|\s+\/>)$/ |
删除代码\\注释 | (?<!http:|\S)//.*$ |
Unicode编码中的汉字范围 | /^[\u2E80-\u9FFF]+$/ |