JavaScript正则的使用技巧

JavaScript正则表达式使用

作者的话

​ 正则表达式在日常工作中真的非常有用,如果想要用复杂的逻辑处理一大段字符串,那么你必须学会使用正则表达式。

​ 本文会通过很多个对字符串使用复杂逻辑处理的例子,带领大家稍微学会正则表达式,但真的想要学好使用正则表达式,一定要在日常生活中经常使用正则,不要再使用循环、splice等方法处理字符串!

​ 另外,本文不会贴上冗长的正则的一些语法、元字符、运算符优先级一类的东西,所以我希望你有这方面的知识,但是如果没有的话也不需要现在去学,我会在使用的例子中详细讲解我所使用的每一个符号的意义

​ 还有,请不要嫌我啰嗦。对同样的字符串可以使用不同的正则,也就是说我本文一些例子题解并不是唯一答案,对于正则来说并不需要唯一答案,只要你写出来,能够正常使用那就够了!

JavaScript 正则的使用

RegExp 对象

​ 首先,我们要使用JavaScript中的正则,那我们必须要构建正则对象,也就是RegExp

​ 有三种构建方式。

/pattern/flags
new RegExp(pattern [, flags])
RegExp(pattern [, flags])

pattern:你书写的正则表达式。

flags:标志,可以不指定。详细参数

正则常用方法

这一节会介绍我们在使用正则处理字符串的时候经常使用的方法。如果不了解请不要跳过,耐心一点。

RegExp.prototype.exec()

exec()方法在一个指定字符串中执行一个搜索匹配。返回一个结果数组或 null

参数
regexObj.exec(str)//str要匹配正则表达式的字符串
返回值

着重介绍一下返回值。

如果匹配成功,exec() 方法返回一个数组,并更新正则表达式对象的属性。返回的数组将完全匹配成功的文本作为第一项,将正则括号里匹配成功的作为数组填充到后面。

如果匹配失败,exec() 方法返回 null

对象 属性/索引 描述
result [0] 匹配的全部字符串
[1], ...[*n*] 括号中的分组捕获 [1] = Brown[2] = Jumps
index 匹配到的字符位于原始字符串的基于0的索引值 4
input 原始字符串 The Quick Brown Fox Jumps Over The Lazy Dog
re lastIndex 下一次匹配开始的位置
ignoreCase 是否使用了 “i” 标记使正则匹配忽略大小写 true
global 是否使用了 “g” 标记来进行全局的匹配. true
multiline 是否使用了 “m” 标记使正则工作在多行模式(也就是,^ 和 $ 可以匹配字符串中每一行的开始和结束(行是由 \n 或 \r 分割的),而不只是整个输入字符串的最开始和最末尾处。) false
source 正则匹配的字符串 quick\s(brown).+?(jumps)
使用例

为了不弹射起步,我们先使用它处理一些基本的操作,比如我们查找句号后面的两个汉字。

let str = "迢迢牵牛星,皎皎河汉女。纤纤擢素手,札札弄机杼。终日不成章,泣涕零如雨;河汉清且浅,相去复几许!盈盈一水间,脉脉不得语。"
let pattern = /。([\u4e00-\u9fa5]{2})/g
while((result = pattern.exec(str))!=null){
    console.log(result[1])
}
//纤纤
//终日

做了什么?

先看正则表达式,我说下其中每个字符的意义。

首先看g,这是我们构建RegExp对象的flags属性,g表示我们全局匹配;找到所有匹配,而不是在第一个匹配后停止。(动手能力强的同学先不要着急去掉g运行)

回头看正则正文,。(some thing),我们按层看,首先是当然它会匹配一个,接着,()括号代表的意思是,我们不仅匹配里面的东西,而且还要拿到括号中匹配成功的字符串。记住了吗()表示不仅匹配 而且保存。那么保存在哪?保存在exec()方法的返回值里面的[1]、[2]、[3]、....中。

再往下,[\u4e00-\u9fa5],[a-z]表示字符范围在a到z之间,那么我们这里的用法就很明显,表示编码在\u4e00-\u9fa5之间的字符。这一般代表汉字范围。

最后{2}代表{2}之前的项目要匹配两个。

ok,说完了正则表达式说一下我们用的方法

我们在while循环中使用了exec,为什么不会死循环?因为我们使用了g全局匹配,要记住pattern是一个正则对象,其内部是有自己的状态的。当我们使用g模式的时候,exec会遍历字符串,返回每一个匹配,直到没有匹配返回null

result[1],还记得我们的()吗?保存的获取匹配项就存在这里。

RegExp.prototype.test()

test() 方法执行一个检索,用来查看正则表达式与指定的字符串是否匹配。返回 truefalse

相比exec方法,test方法要简单不少。

参数
regexObj.test(str)//用来与正则表达式匹配的字符串
返回值

如果正则表达式与指定的字符串匹配 ,返回true;否则false

使用例

这一次我们试着看看字符串是否为规范的邮箱格式!

let str1 = "[email protected]"//我是邮箱
let str2 = "123[456]]]@qq.com"//我不是邮箱
let pattern = /\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}/g
console.log(pattern.test(str1),pattern.test(str2))
//true false

知识点

\w:匹配字母、数字、下划线。等价于’[A-Za-z0-9_]’。

.:匹配除换行符(\n、\r)之外的任何单个字符。要匹配包括 ‘\n’ 在内的任何字符,请使用像"(.|\n)"的模式。

+:匹配前面的子表达式一次或多次。例如,‘zo+’ 能匹配 “zo” 以及 “zoo”,但不能匹配 “z”。+ 等价于 {1,}。

*:匹配前面的子表达式零次或多次。例如,zo* 能匹配 “z” 以及 “zoo”。* 等价于{0,}。

String.prototype.search()

search() 方法执行正则表达式和 String 对象之间的一个搜索匹配。

参数
str.search(regexp)//regexp:一个正则表达式(regular expression)对象。如果传入一个非正则表达式对象 obj,则会使用 new RegExp(obj) 隐式地将其转换为正则表达式对象。
返回值

如果匹配成功,则 search() 返回正则表达式在字符串中首次匹配项的索引;否则,返回 -1

使用例

如果想要获取匹配,我还是比较建议exec()方法,但如果单纯检测是否含有某一子串,search方法也是不错的选择,至少我们在语义化上简洁了不少,对吧?

let str = "迢迢牵牛星,皎皎河汉女。纤纤擢素手,札札弄机杼。终日不成章,泣涕零如雨;河汉清且浅,相去复几许!盈盈一水间,脉脉不得语。"
let pattern = new RegExp("盈盈")
console.log(str.search(pattern))//48
pattern = new RegExp("哈哈")
console.log(str.search(pattern))//-1

String.prototype.replace()

replace() 方法返回一个由替换值(replacement)替换一些或所有匹配的模式(pattern)后的新字符串。模式可以是一个字符串或者一个正则表达式,替换值可以是一个字符串或者一个每次匹配都要调用的回调函数。

参数
str.replace(regexp|substr, newSubStr|function)
/*
regexp (pattern)
一个RegExp 对象或者其字面量。该正则所匹配的内容会被第二个参数的返回值替换掉。
substr (pattern)
一个将被 newSubStr 替换的 字符串。其被视为一整个字符串,而不是一个正则表达式。仅第一个匹配项会被替换。
newSubStr (replacement)
用于替换掉第一个参数在原字符串中的匹配部分的字符串。该字符串中可以内插一些特殊的变量名。参考下面的使用字符串作为参数。
function (replacement)
一个用来创建新子字符串的函数,该函数的返回值将替换掉第一个参数匹配到的结果。参考下面的指定一个函数作为参数。
*/
使用例

replace是一个大杀器,毕竟我们在处理字符串时,不是只查找含有子串,更多的是需要我们替换子串。replace方法能使我们以更清楚的逻辑处理字符串。

//在本例中,我们要将下划线、@、+转单驼峰,如user_model->userModel
let str = "__make@by_id__to+_name"
let pattern = /[@|_|/+]{1,}(\S)/g
console.log(str.replace(pattern,(match,s1)=>{
    return s1.toLocaleUpperCase()
}))
///MakeByIdToName

知识点

/+因为我们要匹配+,但是+本身是正则中的元字符,所以我们要将其转义。

{1,}匹配1次及以上。

(match,s1)=>{}箭头函数,ES6语法。

s1有人好奇它是哪来的吗?这其实就是我们用()匹配获取的。

正则高级技巧

捕获括号(x)

模式 /(foo) (bar) \1 \2/ 中的 ‘(foo)’ 和 ‘(bar)’ 匹配并记住字符串 “foo bar foo bar” 中前两个单词。模式中的 \1\2 表示第一个和第二个被捕获括号匹配的子字符串,即 foobar,匹配了原字符串中的后两个单词。注意 \1\2、…、\n 是用在正则表达式的匹配环节,详情可以参阅后文的 \n 条目。而在正则表达式的替换环节,则要使用像 $1$2、…、$n 这样的语法,例如,'bar foo'.replace(/(...) (...)/, '$2 $1')$& 表示整个用于匹配的原字符串。

非捕获括号(?:x)

匹配 ‘x’ 但是不记住匹配项。这种括号叫作非捕获括号,使得你能够定义与正则表达式运算符一起使用的子表达式。看看这个例子 /(?:foo){1,2}/。如果表达式是 /foo{1,2}/{1,2} 将只应用于 ‘foo’ 的最后一个字符 ‘o’。如果使用非捕获括号,则 {1,2} 会应用于整个 ‘foo’ 单词。

先行断言x(?=y)

匹配’x’仅仅当’x’后面跟着’y’.这种叫做先行断言。

例如,/Jack(?=Sprat)/会匹配到’Jack’仅仅当它后面跟着’Sprat’。/Jack(?=Sprat|Frost)/匹配‘Jack’仅仅当它后面跟着’Sprat’或者是‘Frost’。但是‘Sprat’和‘Frost’都不是匹配结果的一部分。

后行断言(?<=y)x

匹配’x’仅仅当’x’前面是’y’.这种叫做后行断言。

例如,/(?<=Jack)Sprat/会匹配到’ Sprat ‘仅仅当它前面是’ Jack '。/(?<=Jack|Tom)Sprat/匹配‘ Sprat ’仅仅当它前面是’Jack’或者是‘Tom’。但是‘Jack’和‘Tom’都不是匹配结果的一部分。

正向否定查找x(?!y)

仅仅当’x’后面不跟着’y’时匹配’x’,这被称为正向否定查找。

例如,仅仅当这个数字后面没有跟小数点的时候,/\d+(?!.)/ 匹配一个数字。正则表达式/\d+(?!.)/.exec(“3.141”)匹配‘141’而不是‘3.141’

反向否定查找(?<!y)x

仅仅当’x’前面不是’y’时匹配’x’,这被称为反向否定查找。

例如, 仅仅当这个数字前面没有负号的时候,/(?<!-)\d+/ 匹配一个数字。
/(?<!-)\d+/.exec('3') 匹配到 “3”.
/(?<!-)\d+/.exec('-3') 因为这个数字前有负号,所以没有匹配到。

对于上面这些操作,我们经常使用的一般就是(x)(?:x)x(?=y)(?<=y)x

一些使用例子

哦,在这些例子中我使用了一点点TypeScript语法,如果你会运行,那很好。但是如果你不会运行,那你大可重写一遍这些例子,这样可以更深刻记忆~

例一、模板字符串

/**
 * 用属性替换模板字符串
 * @param str 模板字符串
 * @param obj 替换对象
 */
function tempStr(str:string,obj:object):string{
    let p = /\{\$(\S+)\}/g
    return str.replace(p,(match,s1)=>{
        return obj[s1]
    })
}
let str = "My name is {$name},and My path in {$path}!"
let obj = {
    name:"于浩岩",
    path:"北京 回龙观"
}
console.log(tempStr(str,obj))

例二、下划线转单驼峰

/**
 * 下划线转单驼峰
 * 例:a_ba___ca->aBaCa
 * @param str 要转换的字符串
 */
function codeFormet(str:string):string{
    let p1 : RegExp = /_+([a-z])/g
    str = str.replace(p1,(match,s1)=>{
        return s1.toLocaleUpperCase()
    })
    return str;
}
console.log(codeFormet("a_ba____ca_a______"))

例三、名字交换

/**
 * 名字交换
 * 例:“Sam Tom”->"Tom Sam"
 * @param str 替换字符串
 */
function alternatelyName(str:string):string{
    let p:RegExp = /(\S+)\s(\S+)/g
    return str.replace(p,"$2 $1");
}
console.log(alternatelyName("Sam Bob"))

参考

脑瘫码农 纯靠自学 如有错误 望请指正 共同学习 不胜感激

发布了31 篇原创文章 · 获赞 38 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/yhy1315/article/details/100063205