-
Notifications
You must be signed in to change notification settings - Fork 840
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JavaScript正则进阶之路——活学妙用奇淫正则表达式 #20
Comments
欢迎分享奇淫技巧,送1024邀请码。 460df166b05db38d 2017-05-29 12:21:30 未使用 邀请 未使用 邀请 有缘人得。 |
@jawil |
我放出去十分钟之内就被人抢注了,一个邀请码只能注册一次。。。@w550 |
我学正则学的都有心理阴影了……话说,这篇文章为什么加了“玄学”的标签? |
正则就是玄学,很少人愿意去深入研究的知识我觉得都是玄学😄 |
https://github.com/52cik/regex-tuesday |
感觉这种题已经超出能力的范围了,瞎折腾一下还可以,正则表达式匹配回文字符串那个也太那个吧,毫无思路,用js到是很简单😄 |
还有 邀请码吗? 老司机 |
2、 数字格式化问题的 |
恩,改错了,之前下面那个应该是--,结果改成上面的了。。。 @fengyun2 已修正 |
这里提到的判断质数的算法是非常非常慢的——它比最 naïve 的 sqrt(N) 还要慢很多很多。 另外数组去重的算法是错误的,例如字符串以 |
首先感谢反馈和意见。 就上面非正则和正则实现的两种方式的性能我们就事论事,用数据说话,考虑到浏览器控制台的诸多沙箱机制以及安全性等等额外不必要因素,这里测试环境我们选择为Node v6.10.2 先看一个比较小的数字:19,这里贴一下代码: console.time('循环非正则')
function isPrime(num){
if(typeof num !== "number" || !Number.isInteger(num)){
return false
}
if(num == 2){
return true
}else if(num % 2 == 0){
return false
}
let squareRoot = Math.sqrt(num)
for(let i = 3; i <= squareRoot; i += 2) {
if (num % i === 0) {
return false
}
}
return true
}
console.log(isPrime(19))
console.timeEnd('循环非正则')
console.time('正则')
function isPrime(num) {
return !/^1?$|^(11+?)\1+$/.test(Array(num+1).join('1'))
}
console.log(isPrime(19))
console.timeEnd('正则') 输出结果: 看到结果了吧,再来看看稍微大点情况下各自的时间,在数组允许的长度下,这里取123456。 输出结果: 不要以为正则就一定很慢,什么事情都是相对的,最好是用数据说话,哪怕测试的方式不太对,口说无凭,没有足够信服力。 数组去重那块肯定是不完善的,我也说了,用正则属于吃力不讨好,所以最后一个就为了对比,正则也有它不好用的场景,反正二者各有千秋,没有孰好孰坏,合适的就是最好的。 |
@jawil 请您学习一下计算机科学。 您首先要意识到的是,判断质数属于 P,用正则表达式的方法是 指数级别 的算法,即使不用那个 高明 的 P 算法,也可以用 sqrt(N) 的方法,同样比正则表达式具有更优的 渐近时间复杂度。 其次,您的实现是不公平的,正则表达式版本缺少对 num 的检验,循环的版本里面开方会面临浮点误差的问题。对于开方的问题,一种常见的实现是换成 最后,您测量时间的 方法是错误的,因为:
我重新写了一份代码。先贴结果,我的环境是 NodeJS 6.10.3,多次运行结果接近这种排序:
测试的命令是 function isPrimeSqrtN(x)
{
if (x < 2) return false;
for (var i = 2; i * i <= x; ++i)
if (x % i == 0)
return false;
return true;
}
function isPrimeRegex(x)
{
return !/^1?$|^(11+?)\1+$/.test(Array(x+1).join('1'));
}
console.error(isPrimeSqrtN(9));
console.error(isPrimeSqrtN(7));
console.error(isPrimeRegex(9));
console.error(isPrimeRegex(7));
console.time('isPrimeSqrtN(19)');
console.error(isPrimeSqrtN(19));
console.timeEnd('isPrimeSqrtN(19)');
console.time('isPrimeRegex(19)');
console.error(isPrimeRegex(19));
console.timeEnd('isPrimeRegex(19)');
console.time('isPrimeSqrtN(123456)');
console.error(isPrimeSqrtN(123456));
console.timeEnd('isPrimeSqrtN(123456)');
console.time('isPrimeRegex(123456)');
console.error(isPrimeRegex(123456));
console.timeEnd('isPrimeRegex(123456)');
console.time('isPrimeSqrtN(347*347)');
console.error(isPrimeSqrtN(347*347));
console.timeEnd('isPrimeSqrtN(347*347)');
console.time('isPrimeRegex(347*347)');
console.error(isPrimeRegex(347*347));
console.timeEnd('isPrimeRegex(347*347)');
|
@GeeLaw 受教了,我测试的方式不对,正则效率确实慢一些,对于算法这门计算机科学的学习也还有很长的路要走。 |
应该是
|
感谢指出,已更正@wclimb |
感觉挺有意思的。 |
@jsdchenye 两种实现结果都是一样的吧? |
@jawil 我也实现了一下: function formatCash(str) {
return str.split('').reverse().reduce((prev, next, index) => {
return ((index % 3) ? next : (next + ',')) + prev
})
}
console.log(formatCash('1234567890')) // 1,234,567,890 |
@mqyqingfeng |
@mqyqingfeng 感谢回答,这个非常巧妙 |
@jsdchenye 原来是多了个 0,我还以为是逗号的位置不对……😂 |
看着看着怎么突然就开车了。。。 |
用正则进行数组去重也可以这样,只适用字符串数组
|
好像在知乎还是哪里看到的,对于问题二: 数字格式化问题,1234567890 --> 1,234,567,890, |
function format(str){ |
求指点,jquery里有这种代码(?:\d*.|),这里把或放最后是进行什么操作,可以为空吗,我试了好久都找到窍门 |
@huyoo ?: 表示非捕获性分组,这个不影响匹配结果,我们忽略掉这个表达式就变成 var str1 = "1.9";
var str2 = "1";
var patt1 = /(\d*\.|)\d/
console.log(patt1.test(str1)) // true
console.log(patt1.test(str2)) // true |
@mqyqingfeng 原来如此,感谢指点 |
文章吸引人,标题很重要。正则表达式小白前来膜拜学习 |
" test ".trim() //test |
// 获取URL的查询参数, 我见过最精简 |
关于数组去重,我找到一种更简单的思路:
|
这种只适用于重复两个,考虑多个需要完善一下 |
"ab,ab,ab,k,k,k,lf,lf,lf,lf,kjf,kjf,kjf".replace(/(^|\b)([^,]+)(,\2)+(,|$)/g, "$1$2$4") |
"ab,ab,ab,k,k,k,lf,lf,lf,lf,kjf,kjf,kjf".replace(/\b([^,]+)(,\1)+\b/g, "$1") |
原文收录在我的 GitHub博客 (https://github.com/jawil/blog) ,喜欢的可以关注最新动态,大家一起多交流学习,共同进步,以学习者的身份写博客,记录点滴。
实现一个需求的方法很多种,哪种更好,仁者见仁智者见智,这里只提供一种对比的思维来激发大家学习正则的兴趣和养成活用正则的思维。
作为前端开发人员,总会有点自己的奇技淫巧,毕竟前端开发不同于后端,代码全部暴漏给用户不说,代码冗余了少则影响带宽,多则效率降低。正则表达式(Regular Expression),这是一块硬骨头,很难啃,但是啃着又很香。所以今天我也来爆一些正则表达式的奇技淫巧。
正则大法好,正则大法好,正则大法好,重要的事情说三遍。
1、获取链接
https://www.baidu.com?name=jawil&age=23
name的value值非正则实现:
用正则实现:
看不太懂先学习一下这篇文章:[ JS 进阶 ] test, exec, match, replace
2、 数字格式化问题,1234567890 --> 1,234,567,890
非正则实现:
用正则实现:
下面简单分析下正则
/\B(?=(\d{3})+(?!\d))/g
:/\B(?=(\d{3})+(?!\d))/g
:正则匹配边界\B
,边界后面必须跟着(\d{3})+(?!\d)
;(\d{3})+
:必须是1个或多个的3个连续数字;(?!\d)
:第2步中的3个数字不允许后面跟着数字;(\d{3})+(?!\d)
:所以匹配的边界后面必须跟着3*n
(n>=1)的数字。最终把匹配到的所有边界换成
,
即可达成目标。3、去掉字符串左右两边的空格," jaw il " --> “jaw il”
非正则实现:
用正则实现:
4、判断一个数是否是质数 3 --> 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”的整数倍……,而,这正好是我们需要的算素数的算法。现在大家明白了吧。
5、字符串数组去重 ["a","b","c","a","b","c"] --> ["a","b","c"]
这里只考虑最简单字符串的数组去重,暂不考虑,对象,函数,NaN等情况,这种用正则实现起来就吃力不讨好了。
非正则实现:
①ES6实现
②ES5实现
③ES3实现
额,ES4呢。。。对不起,由于历史原因,ES4改动太大,所以被废弃了。
可以看到从ES3到ES6,代码越来越简洁,JavaScript也越来越强大。
用正则实现:
这里我只是抛砖引玉的利用几个例子对比来展现正则表达式的强大,其实正则表达式的应用远远不止这些,这里列出的只是冰山一角,更多的奇淫技巧需要你们来创造,知识点API是有限的,技巧和创造却是无限的,欢迎大家开动脑门,创造或分享自己的奇淫技巧。
学习正则
如果还没有系统学习正则表达式,这里提供一些网上经典的教程供大家学习。
正则表达式(Regular Expression),这是一块硬骨头,很难啃,但是啃着又很香。
正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串。很多地方我们都需要使用正则,所以今天就将一些优秀的教程,工具总结起来。
基本内容
https://en.wikipedia.org/wiki/Regular_expression 了解一样东西,当然先从WIKI开始最好了。
教程
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/ 速查表地址,如下图
The text was updated successfully, but these errors were encountered: