有些童鞋肯定有所疑惑,花了大量時間學習正則表達式,卻發現沒有用武之地,正則不就是驗證個郵箱嘛,其他地方基本上用不上,其實,大部分人都是這種感覺,所以有些人乾脆不學,覺得又難又沒什麼用。殊不知,想要成為程式設計大牛,正規表示式必須玩轉,GitHub上優秀的開源函式庫和框架裡面到處都是強大的正則匹配,當年jQuery作者也被稱為正則小王子。這裡分享一些工作中用到的和自己收集的一些正規表示式的妙用,到處閃耀著開發者智慧的火花。
實現一個需求的方法很多種,哪種更好,仁者見仁智者見智,這裡只提供一種對比的思維來激發大家學習正則的興趣和養成活用正則的思維。
身為前端開發人員,總是會有點自己的奇技淫巧,畢竟前端開發不同於後端,程式碼全部暴漏給用戶不說,程式碼冗餘了少則影響頻寬,多則效率降低。正規表示式(Regular Expression),這是一塊硬骨頭,很難啃,但是啃著又很香。所以今天我也來爆一些正規表示式的奇技淫巧。
正則大法好,正則大法好,正則大法好,重要的事情說三遍。
1、取得連結https://www.baidu.com?name=jawil&age=23 name的value
非正規實作:
##
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
#2、 數字格式化問題,1234567890 --> 1,234,567,890
非正規實作:
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);
( \d{3})+:必須是1個或多個的3個連續數字;
(?!\d):第2步驟中的3個數字不允許後面跟著數字;
(\ d{3})+(?!\d):所以符合的邊界後面必須跟著3*n(n>=1)的數字。
最終把所有配對到的邊界換成,即可達成目標。
3、去掉字串左右兩邊的空格," jaw il " --> “jaw il”
非正規實作:
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"
4、判斷一個數是否為質數3 --> true質數又稱素數。指在一個大於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+$/
第一部分:/^1?$/, 这个部分相信不用我多说了,其表示匹配“空串”以及字串中只有一个“1”的字符串。
第二部分:/^(11+?)\1+$/ ,这个部分是整个表达式的关键部分。其可以分成两个部分,(11+?) 和 \1+$ ,前半部很简单了,匹配以“11”开头的并重复0或n个1的字符串,后面的部分意思是把前半部分作为一个字串去匹配还剩下的字符串1次或多次(这句话的意思是——剩余的字串的1的个数要是前面字串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实现
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也越来越强大。
以上是JavaScript巧用正規表示式實例的詳細內容。更多資訊請關注PHP中文網其他相關文章!