RegExp
NFA, none deterministic finite automaton: 非确定有限状态自动机 : .* DFA, deterministic finite automaton:确定有限状态自动机):
- 优先选择最左的匹配结果
- 替代优先判断
如
.*"用[^"]替代 如 ((?!.)*?),
字符组
\w : [0-9a-zA-Z_] ; \W : [^0-9a-zA-Z_]
\s : 表示空白符,包括空格、水平制表符、垂直制表符、换行符、回车符、换页
符,即[^\t\v\n\r\f]
. : 表示从除换行符、回车符、行分隔符(\u2028)和段分隔符(\u2029)以外的字符,即[^\n\r\u2028\u2029]
表示任意字符:[\d\D], [\w\W], [\s\S]
\n : 第 n 个子捕获匹配的子字符串(【捕获的数目以左括号计数】)
非贪婪匹配
{m,n}?; {m,}? ; ??
【特殊】 /good|nice/分支匹配也是从左往右顺序进行深度搜索进行匹配(所有的正则都是最左匹配)
位置匹配
^, $, (?=p) : /Jack(?=Sprat)/会匹配到'Jack'仅当它后面跟着'Sprat'。/Jack(?=Sprat|Frost)/匹配的'Sprat'和'Frost'都不是匹配结果的一部分。 (?<=p) :/(?<=Jack)Sprat/会匹配到' Sprat '仅仅当它前面是' Jack ' 。 (?!p) : x(?!y) (?<!p) :(?<!y)x
\b :匹配一个词的边界
- /\bm/匹配“moon”中的‘m’;
- /oo\b/并不匹配"moon"中的'oo',因为'oo'被一个“字”字符'n'紧跟着。
- /oon\b/匹配"moon"中的'oon',因为'oon'是这个字符串的结束部分。这样他没有被一个“字”字符紧跟着。
- /\w\b\w/将不能匹配任何字符串,因为在一个单词中间的字符永远也不可能同时满足没有“字”字符跟随和有“字”字符跟随两种情况;同理/(a(?=c)b)/,不可能匹配 a 后面是 c,但为 b 的字符串;/.^/
\B :匹配一个非单词边界 => (?!\b)
tips
- []减少回溯 :
"[^"]* - 位置字符和序列字符优先级比 | 高:
/^abc|bcd$/=>/(^abc)|(bcd$)/ - 需转义字符:
^$.*+?|\\/[]{}=!:-,
String.replace(reg, function(full, key, value){})
Regex 构造函数生成正则的转义字符需要添加: new RegExp('\\d') => /\d/
/asd(\d+)qwe(\d+)/.test("as!asd1231qwe432!dsw");
RegExp.$1; // 1231
RegExp.$2; // 432
RegExp.lastMatch; // asd1231qwe432
RegExp.lastParen; // 432 // 捕获为最后一次()
RegExp.leftContext; // as!
RegExp.rightContext; // !dsw
特殊理解:
// if-then-else匹配
(?(?=condition)(then1|then2|then3)|(else1|else2|else3))
// 可以理解为
(?=condition)(then1|then2|then3) 和 (else1|else2|else3)
匹配示例:
// 后面是 (\d{3})+$ 的间隙
// 每 3 个数字添加逗号 ","
const result = "12345678".replace(/(?=(\d{3})+$)/g, ","); // 12,345,678
// 匹配不是开头的 a,b,c
const regex = /(?!^)[a-c]/, /^(?![a-c])/
// 解析一个完整的url
/^(?:([A-Za-z]+):)?(\/{0,2})([.a-zA-Z\/\d]+)(?::(/d{0, 4})+)\?([a-zA-Z\d]=[a-zA-Z\d])(#[a-zA-Z\d])?$/
计算字符串表达式
var calculate = function(expr) {
expr = expr.replace(/ +/g, '')
const operExp = /\(\d+[+\-*\/]\d+\)|\(-?\d+\)|\d+[*\/]\d+|-?\d+[+-]\d+(?![*\/\d])/
while(operExp.test(expr)) {
expr = expr.replace(operExp, val => Math.floor(eval(val)))
}
return expr
}
// console.log(calculate("3+5/2"))
// console.log(calculate("2-3+4"))
// console.log(calculate("14-13/2"))
匹配最内层标签:
// 外层()仅代表(.)*关联,并不捕获
let reg = /<B>((?!<B>|<\/B>).)*<\/B>/g;
let str = "<B>asdad<B>123123</B>asdasd</B>";
reg.exec(str); // ["<B>123123</B>", "3", index: 8, input: "<B>asdad<B>123123</B>asdasd</B>", groups: undefined]
str.match(reg); // ["<B>123123</B>"]
// 捕获需要再包含()
// 一般使用正向否定查找的方式为x(?!y),但因为*可重复定义该查找方式:x(?=y),x(?!y),(?<!y)x同理
// ((?!<B>|<\/B>).)* => ((?!<B>|<\/B>).)?((?!<B>|<\/B>).)+
let reg2 = /<B>(((?!<B>|<\/B>).)*)<\/B>/g;
reg2.exec(str); // ["<B>123123</B>", "123123", "3", index: 8, input: "<B>asdad<B>123123</B>asdasd</B>", groups: undefined]
getElementsByClassName
// /(^|\s)classname(\s|$)/
function getElementsByClassName(className) {
var elements = document.getElementsByTagName("*");
var regex = new RegExp("(^|\\s)" + className + "(\\s|$)");
var result = [];
for (var i = 0; i < elements.length; i++) {
var element = elements[i];
if (regex.test(element.className)) {
result.push(element);
}
}
return result;
}
exec 和 match 的区别
// 1. exec 为 RegExp 方法, match 是 String 方法
// 2. 当正则无子表达式,且非全局匹配时,两者返回相同;
// 当正则无子表达式,且定义为全局匹配时,match 返回全局匹配;
// 当正则有子表达式,且定义为非全局匹配时,exec 返回整个正则匹配和子表达式匹配,match 返回一次匹配的多个整正则匹配字符串;
// 当正则有子表达式,且定义为全局匹配,match 返回全局匹配的多个整正则匹配字符串;
// 总结:exec 返回与是否有子匹配相关;match 返回与全局,整个字符串匹配相关;
// exec 可多次进行匹配,reg.lastIndex 保存最后一次匹配的索引
// 非全局有子匹配
/.{1}(12)(3)/.exec("asd 123"); // [" 123", "12", "3", index: 3, input: "asd 123", groups: undefined]
"asd 123".match(/.{1}(12)(3)/); // [" 123", "12", "3", index: 3, input: "asd 123", groups: undefined]
// 全局有子匹配
"asd 123a123".match(/.{1}(12)(3)/g); // [" 123", "a123"]
const reg = /.{1}(12)(3)/g,
str = "asd 123a123";
reg.exec(str); // [" 123", "12", "3", index: 3, input: "asd 123a123", groups: undefined] // 下次匹配从index: 3开始
reg.exec(str); // ["a123", "12", "3", index: 7, input: "asd 123a123", groups: undefined]
reg.exec(str); // null : 重置index: 0