正则表达式之 Unicode 匹配特殊字符
首先声明,本文所有的代码都是在ES6下面运行,ES5需要修改之后才能运行,但是本文没有涉及到太多的ES6新特性,而且由于v8对u修饰符不支持,最后的实现也基本是用ES5的知识写的代码。
最初我只是想记录下正则表达式用unicode的方式来匹配特殊字符,写着写着发现v8对u修饰符的不支持,又转而去研究怎么转换字符串到utf-16的格式,在研究怎么转换的过程中发现ES5的正则对unicode编码单元>0x10000的字符串不支持,再转而去实现了一遍对大于0x10000的字符串的转换,特此记录。
之前有遇到过一个实用正则表达式匹配特殊字符的需求,例如一段文本'ab*cd$你好我也好]\nseg$me*ntfault\nhello,world',用户可以选择用*或者$来分割字符串。
在javascript中,$和*都是预定义的特殊字符,不能直接写在正则表达式中,而需要转义,写成/\$/或者/\*/。
我们需要根据用户的选择来写正则表达式,封装成一个函数就是:
functionreg(input){ returnnewRegExp(`\\${input}`) }
这种写法初看上去很美好,将字符都转义之后遇到一些特殊的字符可以匹配,然而现实是残酷的:当用户输入的是n或者t这一类的字符的话,返回的正则表达式为/\n/或者/\t/,匹配的就是所有的制表符,这就违背了用户的初衷。
通常有一种写法就是把所有需要转义的特殊字符都列出来,然后再逐一匹配,这种写法很耗费精力,而且可能因为没有统计到的特殊字符而出现漏匹配的情况。
这个时候unicode就隆重登场了,在JavaScript中,我们也可以用unicode来表示一个字符,例如'a'可以写成'\u{61}','你'也可以写成'\u{4f60}'。
关于unicode的介绍大家可以看Unicode与JavaScript详解
ES5中提供了charCodeAt()方法来返回指定索引处字符的Unicode数值,但是Unicode编码单元>0x10000的除外,ES2015中又增加了一个新的方法codePointAt()可以返回大于0x10000字符串的数值。返回的数值是十进制的,此时我们还需要通过toString(16)转成16进制。
封装之后的函数如下
functiontoUnicode(s){ return`\\u{${s.codePointAt().toString(16)}}` } toUnicode('$')->'\u{24}'
重新封装reg函数为
functionreg(input){ returnnewRegExp(`${toUnicode(input)}`,'u') }
其实写到这里,我希望是对的,但是很不幸,V8不支持RegExp的u修饰符。V8支持的话,写到这里就应该结束了,没关系,这里只是提供一种用unicode的方式来转义特殊字符的思想。
虽然v8不支持u修饰符,作为一个有追求的码农,当然不能止步于此,我们也可以使用其他方法继续把这个完善
functiontoUnicode(s){ vara=`\\u${utf(s.charCodeAt(0).toString(16))}` if(s.charCodeAt(1)) a=`${a}\\u${utf(s.charCodeAt(1).toString(16))}` returna } functionutf(s){ returnArray.from('00').concat(Array.from(s)).slice(-4).join('') } //这里用var而没有用let声明,是因为这些代码直接复制到chrome的控制台下就可以看到执行结果 //测试一下 //toUnicode('a')-->"\u0061" //toUnitcode('��')-->"\ud842\udfb7" functionreg(input){ returnnewRegExp(`${toUnicode(input)}`) } //再测试一下 reg('$').test('$')-->true
以上内容就是毛票票小编给大家分享的正则表达式之Unicode匹配特殊字符