问题来源
在javascript中我们新建一个正则表达式是这样的:
var myRe = /d(b+)d/g;
但是在C++中我们会遇到这种情况:
// regular expression: \d -> matches a digit character
std::regex e1 ("\\d");
// regular expression: \\ -> matches a single backslash (\) character
std::regex e2 ("\\\\");
C++里怎么有这么多\\?在Java新建正则表达式也是一样的,总是遇到好多\\。对于大神可能不屑这种问题,但是对于刚开始学习正则的小白来说,我们今天就好好来扒一扒这个问题。
分析问题
如果仔细看的话,会发现C++在创建正则表达式的时候是通过字符串来创建的。其实javascript也有通过字符串创建正则表达式的方式。如下:
//匹配一个或多个数字或者英文字母同时后面跟一个空格
var re = new RegExp('\\w+\\s', 'g');
这个时候会发现,javascript中也会遇到好多“\\”?根据javascript的前后两种创建正则表达式的方式,我们会发现,问题是跟字符串有关。如果通过字符串去创建正则表达式,会经常遇到多个\\出现的情况。
所以现在的问题是,为什么使用字符串创建正则表达式经常会有\\?这时候我们就要说一说\以及转义字符(Escape Character)了。
转义字符(Escape Character)
首先,转义字符是一个字符,然后当转义字符后跟其他的字符或者子字符串的时候(我们称之为escape sequence),会对之后的字符进行特殊的解释。另外,转义字符本身通常没有任何含义,因此escapse sequence通常会有两个以上的字符。有关转义字符的Wiki链接
好,我们现在来看例子,在现代编程语言例如C, C++, Java, JavaScript的字符串中,我们都使用‘\’来作为转义字符。
- \’ 表示 single quote
- \” 表示 double quote
- \\表示 backslash
- \n 表示 new line
- \t 表示 tab
- \b 表示 backspace
从上面可知,转义字符通常用两种用法,一种情况是和特殊字符组合,此时特殊字符不再有特殊含义。比如上面的 “(double quote),通常情况下,我们把它作为字符串的分界符,但是如果和转义字符组合使用 \“时,不再有特殊含义。另一种情况是,转义字符和普通字符组合使用,此时会用来表示某些特殊含义,比如\n表示新起一行。
但是需要注意的是,转义字符不只是\。
比如在URI(Uniform Resource Identifer)中,我们使用%作为转义字符(看这里)。在HTML中我们使用&作为转义字符(看这里)。
好了,现在我们知道什么是转义字符了。然后我们再回来看我们的问题,为什么new RegExp('\\w+\\s', 'g')
中有两个\\;,首先在这句JS的语句中有一个字符串,这个字符串被解析后实际表示\w+\s,然后是被正则表达式的解析器解析(在正则表达式中,\同样作为转义字符),其中\w表示一个数字或者英文字母(alphanumeric),+是一个特殊字符表示一个或多个,\s表示一个white space,所以整个正则表达式匹配一个或多个数字或者英文字母并且后面跟一个white space的情况,比如“abs ”。仔细看上面的过程,这里包含了两次解析过程,首先是一次字符串的解析,然后是一次正则表达式的解析,而且这两个过程中都是使用\作为转义字符。然后在正则表达式中经常要用到\,但是如果使用字符串创建正则表达式,单个\在字符串中没有任何含义(因为\是转义字符,单独使用没有意义,上面已经提到过),所以在字符串中我们需要使用\\来表示\,即上面的提到的转义字符通常使用的第二种情况,取消特殊字符的特殊含义。所以,我们会经常在字符串表达的正则表达式中看到多个\\。
快速写一个正则表达式
既然我们已经弄清楚了为什么。即看到一个字符串表达的正则表达式如何分析其含义(两次解析过程)。现在我们再来看,如何快速写一个正则表达式。
首先我们先写出我们想要的正则表达式,比如匹配两个数字相加的表达式,举个例子 123+234。那么正则表达式应该是\d+\+\d+。其中\d+表示一个或多个数字,然后是\+,匹配一个加号(因为+在正则表达式中是一个特殊字符,所以需要使用\来消除其特殊含义),然后又是一个\d+,匹配一个或多个数字。第二步,我们要写成字符串的形式,在字符串中单个\没有意义,我们要使用\\代替\,随意最后的形式为“\d+\+\d+”。
另外一种更特殊的情况是,我们要匹配一个\字符。然后还是经过上面的两个步骤,第一步,写出正则表达式,即\\;,因为\在正则表达式中是转义字符,单独使用没有意义,我们要使用\\代替\。第二步,写成字符串形式的正则表达式。即\\\\。同样的原因,\在字符串中也是转义字符,单独使用没有意义,所以每个\都要替换成\\,最终的形式即\\\\。
Reference
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
http://www.cplusplus.com/reference/regex/ECMAScript/
https://en.wikipedia.org/wiki/Escape_character#ASCII_escape_character