RegExp vs includes vs match

前言

在筛选字串时,有不少选择提供我们使用,除了使用常见的直接比对字串的 includes 之外,还有 Regular Expression(以下简称 RegExp)及match 可以使用,他们的使用方法为何?我们到底该用谁?,今天94要来pk啦!看完这篇文章可以帮助你厘清自己比较适合用哪一个及他们之间的不同.
本文章会简单介绍includes,RegExp及match,如果想直接知道结果可以直接从match vs RegExp vs includes开始看

浏览器大不同

此范例使用 indexOf 及 RegExp 进行 PK,可以了解不同浏览器执行结果不同的事实(如果你过去很喜欢使用 RegExp 请先冷静点,并且不要在排斥使用 safari 开发了)
https://ithelp.ithome.com.tw/upload/images/20220316/20144476LNUoRRYTvT.png
图片来源
这边可以测试一下自己爱用的浏览器

下图为个人电脑在 Chrome 及 Safari 使用 measurethat.net 执行後的结果,分别是左方的 Chrome(version 98.0.4758.80)及右方的 Safari(version 15.1)
可以看出虽然 test 及 includes 在 Chrome 表现的比较好,不过 match 则是 Safari 表现得比较好
https://ithelp.ithome.com.tw/upload/images/20220316/201444763vuD9kzRTW.png

RegExp

在 filter 输入[,\和(都可以把前端搞炸!!!!? but why?
原因为在正规表示式中有'['开头 就一定要有']'结尾,'('同理,也一定要有')'结果,而''则是要使用另一个''结尾或其余特殊字元表示法,在了解 RegExp 的规则後,介绍一下常见的 method 分别是 test 和 exec
[的详细说明
(的详细说明
\的详细说明

test

test:检查字串中是否有符合的部分,有的话回传 true 没有则回传 false

const str = 'hello';
const str2 = 'hello2';

// 寻找字串中有有lo的结果
const regex = new RegExp('lo');
// 寻找字串中有有Lo或lo的结果
const regexAddFlags = new RegExp('LO', 'i');
// 寻找字串中有有0~9的结果
const regexUseSpecialChar = new RegExp(/\d/);

console.log(regex.test(str));
// expected output: true
console.log(regex.test(str2));
// expected output: true

console.log(regexAddFlags.test(str));
// expected output: true
console.log(regexAddFlags.test(str2));
// expected output: true

console.log(regexUseSpecialChar.test(str));
// expected output: false

console.log(regexUseSpecialChar.test(str2));
// expected output: true

RegExp 中常见的 Flag

exec

exec:检查字串中是否有符合的部分,有的话以阵列的方式回传,没有则回传 null

const str = 'hello';
const str2 = 'hello2';

// 寻找字串中有有lo的结果
const regex = new RegExp('lo');
// 寻找字串中有有Lo或lo的结果
const regexAddCaseInsensitive = new RegExp('LO', 'i');
// 寻找字串中有有0~9的结果
const regexUseSpecialChar = new RegExp(/\d/);

console.log(regex.exec(str));
// expected output: ["lo"]
console.log(regex.exec(str2));
// expected output: ["lo"]

console.log(regexAddCaseInsensitive.exec(str));
// expected output: ["lo"]
console.log(regexAddCaseInsensitive.exec(str2));
// expected output: ["lo"]

console.log(regexUseSpecialChar.exec(str));
// expected output: null

console.log(regexUseSpecialChar.exec(str2));
// expected output: ["2"]

includes

和 RegExp 的 test 很类似,都是检查字串中是否有符合的部分,有的话回传 true 没有则回传 false,不同的是不能使用 Flag 或是正规表示的内容(如上面范例中的'/\d/').因此,想要达到 RegExp 不区分大小写的搜寻法可能要搭配 toUpperCase 或 toLowercase 才能达到,在 code 里看起来会比较罗唆一些

const str = 'hello';
console.log(str.includes('lo'));
// expected output: true
console.log(str.includes('Lo'));
// expected output: false

const strToUpperCase = 'hello'.toUpperCase();
console.log(strToUpperCase.includes('lo'.toUpperCase()));
// expected output: true
console.log(strToUpperCase.includes('LO'.toUpperCase()));
// expected output: true

match

和 RegExp 的 exec 很类似,都是检查字串中是否有符合的部分,有的话以阵列的方式回传,没有则回传 null,同样可以使用正规表示的内容(如上面范例中的'/\d/')但不能使用 Flag.因此,想要达到 RegExp 不区分大小写的搜寻法可能要搭配 toUpperCase 或 toLowercase 或是使用正规法式法才能达到,在 code 里看起来会比较罗唆一些

const str = 'hello';
const str2 = 'hello2';

console.log(str.match('lo'));
// expected output: ["lo"]
console.log(str.match('Lo'));
// expected output: null
console.log(str2.match(/\d/));
// expected output: ["2"]

const strToUpperCase = 'hello'.toUpperCase();
console.log(strToUpperCase.match('lo'.toUpperCase()));
// expected output: ["LO"]
console.log(strToUpperCase.match('LO'.toUpperCase()));
// expected output: ["LO"]

match vs RegExp vs includes

终於看完了他们三个的使用介绍觉得讲了那麽多废话 我只想知道到底该用哪个而已的人请冷静点,接着就是最重要的 PK 环节了,不过在三个大 PK 之前,我们先拿 match 跟 RegExp 进行 PK 就好

match vs RegExp(test)

我们先来看一张 match 和 RegExp 的比较图
https://ithelp.ithome.com.tw/upload/images/20220316/20144476YDJsF7AiFl.png
(ops/sec = operate per second)
图片来源

MDN告诉我们以下三点:

  • If you need to know if a string matches a regular expression RegExp, use RegExp.test().
  • If you only want the first match found, you might want to use RegExp.exec() instead.
  • If you want to obtain capture groups and the global flag is set, you need to use RegExp.exec() or String.prototype.matchAll() instead.

参考资料:来自 MDN 的金玉良言
懒人包:如果只想知道是否符合条件的话就用test,如果想知道第一个及全部符合的是谁都用exec即可.

通通来 PK

看完了 match 和 RegExp 我们在把 includes 加进来一起做比较,下面有两张图,我们一张一张看
在第一张图中 RegExp 我们执行了两次分别是有加入 Flag 和没有加入的,可以在图中其实两者的表现并没有相差太多
在整理後的表现优劣排名为:includes>RegExp(没有 Flag)>RegExp(有 Flag)>match.
https://ithelp.ithome.com.tw/upload/images/20220316/20144476LfI96iIY8s.png
但是在第二张图中的排行结果尽然变成:RegExp(有 Flag)>RegExp(没有 Flag)>match>includes.
https://ithelp.ithome.com.tw/upload/images/20220316/20144476diLHRuUZVn.png

P.S. 以上结果皆是使用 JSBench.Me 测试的结果

conclusion

讲了那麽多,我们确定了 match 和 RegExp 在 MDN 的建议下,我们该使用 RegExp,但 includes 和 RegExp 到底该用谁比较好?
个人的观点是,RegExp 和 includes 用谁都好,了解使用情境比较重要,在 Select 类型的搜寻可以大胆的使用 RegExp.但使用 input 提供使用者输入关键字搜寻时,请避免会造成 RegExp 错误的符号出现在画面上,可能会引导使用者在搜寻时输入,进而导致页面爆炸的悲剧发生,毕竟我们没办法控制使用者照着我们期望方式的输入.
说了那麽多,若执意(明知山有虎,偏向虎山行)要使用RegExp请记得遵照以下武林秘笈
武林秘笈:
Escaping user input that is to be treated as a literal string within a regular expression—that would otherwise be mistaken for a special character—can be accomplished by simple replacement:

function escapeRegExp(string) {
  return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
}

参考资料:来自 MDN 的武林秘笈

// 先看只使用一个'['会出错的范例,在经过武林秘笈的调教後,功能的正常
const replaceStr ='[123'.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
const regex = new RegExp(replaceStr);
console.log(replaceStr)
// expected output: "\[123"
console.log(regex.test('[123'));
// expected output: true
console.log(regex.test('[1223'));
// expected output: false

// 开始耍白烂丢一堆原本会出错的'['跟'(',也在经过武林秘笈的调教後,非常的正常
const replaceStr2 ='[123([('.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
const regex2 = new RegExp(replaceStr2);
console.log(replaceStr2)
// expected output: "\[123\(\[\("
console.log(regex2.test('[123([('));
// expected output: true
console.log(regex2.test('[123('));
// expected output: false

// 以上看起来都很美好,不过实际上还是有些特殊的例子 
// 例如下面的范例 其实我们不希望'a\[123'被找出来  但它还是会被找到.此外,只输入一个'\'还是会让js直接爆炸
const replaceStr3 = 'a['.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')  // "a\["
const replaceStr4 = 'a\['.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')  // "a\["
const regex3 = new RegExp(replaceStr3);

console.log(replaceStr3 === replaceStr4)
// expected output: true
console.log(regex3.test('a[123'));
// expected output: true
console.log(regex3.test('a\[123'));
// expected output: true

<<:  AWS Academy LMS 教材使用 - 教师

>>:  python-opencv 进行饼乾烤焦检测

Day 26 讨论 AI 深度学习论点

大家好~~欢迎来到第二十六篇 聊聊 AI 相关论点 本篇呢,来跟大家分享之前本人有做过一个跟车子有关...

[2021铁人赛 Day25] Web Exploitation Web渗透题目 01

引言 今天我们来解 Web 渗透 ( 渗透测试 ) 的题目, 在这之前,你需要先初步了解 HTTP...

[Day27]What is mapping?

hi!今天要介绍mapping!其实mapping很像一个hash table,有很多时候都会有一...

Day 20 2D Arrays

在Java程序设计中,有时一维阵列无法计算较多且较复杂的,这时我们需要二维阵列,例如要产生一个阵列A...

Swift 新手-iPhone 界面设计

在设计 App UI 画面的时候,因 iPhone 有许多不同的机型、萤幕尺寸,从哪个萤幕尺寸开始才...