原文收录在我的 GitHub 博客 (https://github.com/jawil/blog) ,喜欢的可以关注最新动态,大家一起多交流学习,共同进步,以学习者的身份写博客,记录点滴。
有些童鞋肯定有所疑惑,花了大量时间学习正则表达式,却发现没有用武之地,正则不就是验证个邮箱嘛,其他地方基本用不上,其实,大部分人都是这种感觉,所以有些人干脆不学,觉得又难又没多大用处。殊不知,想要成为编程大牛,正则表达式必须玩转,GitHub 上优秀的开源库和框架里面到处都是强大的正则匹配,当年 jQuery 作者也被称为正则小王子。这里分享一些工作中用到的和自己收集的一些正则表达式的妙用,到处闪耀着开发者智慧的火花。
实现一个需求的方法很多种,哪种更好,仁者见仁智者见智,这里只提供一种对比的思维来激发大家学习正则的兴趣和养成活用正则的思维。
作为前端开发人员,总会有点自己的奇技淫巧,毕竟前端开发不同于后端,代码全部暴漏给用户不说,代码冗余了少则影响带宽,多则效率降低。正则表达式(Regular Expression),这是一块硬骨头,很难啃,但是啃着又很香。所以今天我也来爆一些正则表达式的奇技淫巧。
name 的 value 值
- https://www.baidu.com?name=jawil&age=23
- function getParamName(attr) {
- let search = window.location.search // "?name=jawil&age=23"
- let param_str = search.split('?')[1] // "name=jawil&age=23"
- let param_arr = param_str.split('&') // ["name=jawil", "age=23"]
- let filter_arr = param_arr.filter(ele => { // ["name=jawil"]
- return ele.split('=')[0] === attr
- })
- return decodeURIComponent(filter_arr[0].split('=')[1])
- }
- console.log(getParamName('name')) // "jawil"
- function getParamName(attr) {
- let match = RegExp(` [ ? &] $ {
- attr
- } = ([ ^ &] * )`) //分组运算符是为了把结果存到exec函数返回的结果里
- .exec(window.location.search)
- //["?name=jawil", "jawil", index: 0, input: "?name=jawil&age=23"]
- return match && decodeURIComponent(match[1].replace(/\+/g, ' ')) // url中+号表示空格,要替换掉
- }
- console.log(getParamName('name')) // "jawil"
看不太懂先学习一下这篇文章:[[JS 进阶] test, exec, match, replace]( https://segmentfault.com/a/11...
- let test = '1234567890'
- function formatCash(str) {
- let arr = []
- for (let i = 1; i < str.length; i++) {
- if (str.length % 3 && i == 1)
- arr.push(str.substr(0, str.length % 3))
- if (i % 3 === 0)
- arr.push(str.substr(i - 2, 3))
- }
- return arr.join(',')
- }
- console.log(formatCash(test)) // 1,234,567,890
- let test1 = '1234567890'
- let format = test1.replace(/\B(?=(\d{3})+(?!\d))/g, ',')
- console.log(format) // 1,234,567,890
下面简单分析下正则
:
- /\B(?=(\d{3})+(?!\d))/g
:正则匹配边界
- /\B(?=(\d{3})+(?!\d))/g
,边界后面必须跟着
- \B
;
- (\d{3})+(?!\d)
:必须是 1 个或多个的 3 个连续数字;
- (\d{3})+
:第 2 步中的 3 个数字不允许后面跟着数字;
- (?!\d)
:所以匹配的边界后面必须跟着
- (\d{3})+(?!\d)
(n>=1)的数字。
- 3*n
最终把匹配到的所有边界换成
即可达成目标。
- ,
- function trim(str) {
- let start,
- end
- for (let i = 0; i < str.length; i++) {
- if (str[i] !== ' ') {
- start = i
- break
- }
- }
- for (let i = str.length - 1; i > 0; i--) {
- if (str[i] !== ' ') {
- end = i
- break
- }
- }
- return str.substring(start, end - 1)
- }
- let str = " jaw il "console.log(trim(str)) // "jaw il"
- function trim(str) {
- return str.replace(/(^\s*)|(\s*$)/g, "")
- }
- let str = " jaw il "
- console.log(trim(str)) // "jaw il"
质数又称 素数 。指在一个大于 1 的自然数中,除了 1 和此整数自身外,没法被其他自然数整除的数。
- function isPrime(num) {
- // 不是数字或者数字小于2
- if (typeof num !== "number" || !Number.isInteger(num)) {
- // Number.isInterget 判断是否为整数
- return false
- }
- //2是质数
- if (num == 2) {
- return true
- } else if (num % 2 == 0) { //排除偶数
- return false
- }
- //依次判断是否能被奇数整除,最大循环为数值的开方
- let squareRoot = Math.sqrt(num)
- //因为2已经验证过,所以从3开始;且已经排除偶数,所以每次加2
- for (let i = 3; i <= squareRoot; i += 2) {
- if (num % i === 0) {
- return false
- }
- }
- return true
- }
- console.log(isPrime(19)) // true
- function isPrime(num) {
- return ! /^1?$|^(11+?)\1+$/.test(Array(num + 1).join('1'))
- }
- console.log(isPrime(19)) // true
要使用这个正规则表达式,你需要把自然数转成多个 1 的字符串,如:2 要写成 "11", 3 要写成 "111", 17 要写成 "11111111111111111",这种工作使用一些脚本语言可以轻松的完成,JS 实现也很简单,我用
这种方式实现了一下。
- Array(num+1).join('1')
一开始我对这个表达式持怀疑态度,但仔细研究了一下这个表达式,发现是非常合理的,下面,让我带你来细细剖析一下是这个表达式的工作原理。
首先,我们看到这个表达式中有 "|",也就是说这个表达式可以分成两个部分:
和
- /^1?$/
- /^(11+?)\1+$/
可见这个正规则表达式是取非素数,要得到素数还得要对整个表达式求反。通过上面的分析,我们知道,第二部分是最重要的,对于第二部分,举几个例子,
示例一:判断自然数 8。我们可以知道,8 转成我们的格式就是 "11111111",对于 (11+?) ,其匹配了 "11",于是还剩下 "111111",而 1+$ 正好匹配了剩下的 "111111",因为,"11" 这个模式在 "111111" 出现了三次,符合模式匹配,返回 true。所以,匹配成功,于是这个数不是质数。
示例二:判断自然数 11。转成我们需要的格式是 "11111111111"(11 个 1),对于 (11+?) ,其匹配了 "11"(前两个 1),还剩下 "111111111"(九个 1),而 1+$ 无法为 "11" 匹配那 "九个 1",因为 "11" 这个模式并没有在 "九个 1" 这个串中正好出现 N 次。于是,我们的正则表达式引擎会尝试下一种方法,先匹配 "111"(前三个 1),然后把 "111" 作为模式去匹配剩下的 "11111111"(八个 1),很明显,那 "八个 1" 并没有匹配 "三个 1" 多次。所以,引擎会继续向下尝试…… 直至尝试所有可能都无法匹配成功。所以 11 是素数。
通过示例二,我们可以得到这样的等价数算算法,正则表达式会匹配这若干个 1 中有没有出现 "二个 1" 的整数倍,"三个 1" 的整数倍,"四个 1" 的整数倍……,而,这正好是我们需要的算素数的算法。现在大家明白了吧。
这里只考虑最简单字符串的数组去重,暂不考虑,对象,函数,NaN 等情况,这种用正则实现起来就吃力不讨好了。
- ①ES6实现
- let str_arr = ["a", "b", "c", "a", "b", "c"]
- function unique(arr) {
- return [...new Set(arr)]
- }
- console.log(unique(str_arr)) // ["a","b","c"]
- ②ES5实现
- var str_arr = ["a", "b", "c", "a", "b", "c"]
- function unique(arr) {
- return arr.filter(function(ele, index, array) {
- return array.indexOf(ele) === index
- })
- }
- console.log(unique(str_arr)) // ["a","b","c"]
- ③ES3实现
- var str_arr = ["a", "b", "c", "a", "b", "c"]
- function unique(arr) {
- var obj = {},
- array = []
- for (var i = 0,
- len = arr.length; i < len; i++) {
- var key = arr[i] + typeof arr[i]
- if (!obj[key]) {
- obj[key] = true array.push(arr[i])
- }
- }
- return array
- }
- console.log(unique(str_arr)) // ["a","b","c"]
额,ES4 呢。。。对不起,由于历史原因,ES4 改动太大,所以被废弃了。
可以看到从 ES3 到 ES6,代码越来越简洁,JavaScript 也越来越强大。
- var str_arr = ["a", "b", "c", "a", "b", "c"]
- function unique(arr) {
- return arr.sort().join(",,").
- replace(/(,|^)([^,]+)(,,\2)+(,|$)/g, "$1$2$4").
- replace(/,,+/g, ",").
- replace(/,$/, "").
- split(",")
- }
- console.log(unique(str_arr)) // ["a","b","c"]
正则表达式(Regular Expression),这是一块硬骨头,很难啃,但是啃着又很香。
正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串。很多地方我们都需要使用正则,所以今天就将一些优秀的教程,工具总结起来。
https://en.wikipedia.org/wiki/Regular_expression 了解一样东西,当然先从 WIKI 开始最好了。
- // Regular Expression examples
- I had a \S+ day today
- [A-Za-z0-9\-_]{3,16}
- \d\d\d\d-\d\d-\d\d
- v(\d+)(\.\d+)*
- TotalMessages="(.*?)"
- <[^<>]>
http://deerchao.net/tutorials/regex/regex.htm 30 分钟入门教程,网上流传甚广
https://qntm.org/files/re/re.html 55 分钟教程【英文】,
http://regex.learncodethehardway.org/book/ 一本简单的书,每一节就是一块内容
https://swtch.com/~rsc/regexp/regexp1.html 正则匹配原理解析
http://stackoverflow.com/tags/regex/info stackoverflow 正则标签,标签下有值得点击的链接,一些典型的问题
http://regexr.com/ 正则学习测试于一身
https://developer.mozilla.org/zh-CN/docs/web/JavaScript/Guide/Regular_Expressions MDN 出品,JavaScript 方面内容
https://regex101.com/ in JavaScript, Python, PCRE 16-bit, generates explanation of pattern
https://www.debuggex.com/ 正则验证测试,清晰明了
https://mengzhuo.org/regex/ 中文版正则验证测试
http://refiddle.com/ 测试工具
http://myregexp.com/ 也是测试工具,都可以试一试
http://regex.alf.nu 闯关模式练习正则表达式,完成一个个正则匹配的测验
http://regexone.com/ 通过实际练习掌握正则表达式
https://regexcrossword.com/ 正则挑战,有不同难度,很丰富
http://callumacrae.github.io/regex-tuesday/ 正则挑战,完成正则匹配要求
https://msdn.microsoft.com/zh-cn/library/az24scfc.aspx MSDN 微软出品
http://www.jb51.net/tools/regex.htm 常用正则表达式,如匹配网址、日期啊这种,这个谷歌一搜很多的
https://www.cheatography.com/davechild/cheat-sheets/regular-expressions/ 速查表地址,如下图
来源: http://www.tuicool.com/articles/7b2memY