正则表达式学习总结(四)
Opened this issue · 0 comments
Rashomon511 commented
正则表达式的构建
使用正则的三个前提:是否能使用正则? 是否有必要使用正则? 是否有必要构建一个复杂的正则?
在回答完以上三个问题后再考虑使用正则表达式
平衡法则
• 匹配预期的字符串
• 不匹配非预期的字符串
• 可读性和可维护性
• 效率
示例:
匹配固定电话:
let regex = /^(0\d{2,3}-?|\(0\d{2,3}\))[1-9]\d{6,7}$/
匹配浮点数
let regex = /^[+-]?(\d+\.\d+|\d+|\.\d+)$/
正则表达式的运行分为如下的阶段
-
- 编译;
-
- 设定起始位置;
-
- 尝试匹配;
-
- 匹配失败的话,从下一位开始继续第 3 步;
-
- 最终结果:匹配成功或失败。
提升效率的方法:
- 可以使用具体型字符组来代替通配符,来消除回溯
- 匹配字符串 123"abc"456 中的 "abc",/"."/可以修改为/"[^"]"/
- 使用非捕获型分组
- /^[-]?(\d.\d+|\d+|.\d+)$/ 可以修改成:/^[-]?(?:\d.\d+|\d+|.\d+)$/
- 独立出确定字符
- /a+/ 可以修改成 /aa*/
- 提取分支公共部分
- 比如,/^abc|^def/ 修改成 /^(?:abc|def)/。 又比如, /this|that/修改成 /th(?:is|at)/
- 减少分支的数量,缩小它们的范围
- /red|read/ 可以修改成 /rea?d/
正则表达式编程
正则表达式的四种操作: 验证、切分、提取、替换
- 验证:有没有匹配,是不是匹配上,判断是否的操作,即称为“验证”
- 切分:就是把目标字符串,切成一段一段的
- 提取: 通常要使用分组引用(分组捕获)功能,提取部分匹配的数据
- 替换:在 JavaScript 中,使用 replace 进行替换
正则操作的方法
字符串实例 4 个,正则实例 2 个
- String#search
- String#split
- String#match
- String#replace
- RegExp#test
- RegExp#exec
search 和 match 的参数问题
search 和 match,会把字符串转换为正则的
var string = "2017.06.27";
// 效果相同
console.log( string.search("\\.") ); // 4
console.log( string.search(/\./) ); //4
// 效果相同
console.log( string.match("\\.") ); // [".", index: 4, input: "2017.06.27"]
console.log( string.match(/\./) ); // [".", index: 4, input: "2017.06.27"]
match 返回结果的格式问题
没有 g,返回的是标准匹配格式,即,数组的第一个元素是整体匹配的内容,接下来是分组捕获的内容,然 后是整体匹配的第一个下标,最后是输入的目标字符串,有 g,返回的是所有匹配的内容,没有匹配时,不管有无 g,都返回 null
var string = "2017.06.27";
var regex1 = /\b(\d+)\b/;
var regex2 = /\b(\d+)\b/g;
console.log( string.match(regex1) );
console.log( string.match(regex2) );
// => ["2017", "2017", index: 0, input: "2017.06.27"]
// => ["2017", "06", "27"]
exec 比 match 更强大
exec 方法可以解决,正则没有 g 时使用 match 返回的信息比较多。但是有 g 后,就没有关键的信息 index 带来的问题。exec 方法可以接着上一次匹配后继续匹配
修饰符 g,对 exex 和 test 的影响
有g时都是从 lastIndex位置开始匹配,匹配成功后每次都会修改 lastIndex。没有 g,自然都是从字符串第 0 个字符处开始尝试匹配
test 整体匹配时需要使用 ^ 和 $
整体匹配,正则前后需要添加开头和结尾
console.log( /123/.test("a123b") );
// => true
console.log( /^123$/.test("a123b") );
// => false
console.log( /^123$/.test("123") );
// => true
使用构造函数需要注意的问题
一般不推荐使用构造函数生成正则,而应该优先使用字面量。因为用构造函数会多写很多 \
修饰符
- g:全局匹配,即找到所有匹配的,单词是 global。
- i: 忽略字母大小写,单词是 ingoreCase。
- m :多行匹配,只影响 ^ 和 $,二者变成行的概念,即行开头和行结尾。单词是 multiline。
构造函数属性
- RegExp.input | 最近一次目标字符串 | RegExp["$_"]
- RegExp.lastMatch | 最近一次匹配的文本 | RegExp["$&"]
- RegExp.lastParen | 最近一次捕获的文本 | RegExp["$+"]
- RegExp.leftContext | 目标字符串中lastMatch之前的文本 | RegExp["$`"]
- RegExp.rightContext | 目标字符串中lastMatch之后的文本 | RegExp["$'"]
示例:
使用构造函数生成正则表达式
<p class="high">1111</p>
<p class="high">2222</p>
<p>3333</p>
<script>
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;
}
var highs = getElementsByClassName('high');
highs.forEach(function (item) {
item.style.color = 'red';
});
</script>
使用字符串保存数据
var utils = {};
"Boolean|Number|String|Function|Array|Date|RegExp|Object|Error".split("|").forEach(fun
ction (item) {
utils["is" + item] = function (obj) {
return {}.toString.call(obj) == "[object " + item + "]";
}; });
console.log( utils.isArray([1, 2, 3]) );
// => true