Eloquent JavaScript 笔记 九: Regular Expressions(上)

来源:互联网 发布:formal mac 编辑:程序博客网 时间:2024/06/03 21:34

原书链接:http://eloquentjavascript.net/09_regexp.html

1. Creating a regular expression

创建一个RegExp对象,有两种方法:

var re1 = new RegExp("abc");   // 双引号中是一个标准的字符串

var re2 = /abc/;   // 以 / 包起来,所以,要在内部放 / 需要用反斜线转义。

在第二种方法中,特殊字符也需要用反斜线转义,但有一点和普通字符串不同:反斜线本身不需要转义。

正则表达式中有自己的特殊字符,如:+, *, ? 等,要想保持原意,需要在前面加反斜线,如:

var eighteenPlus = /eighteen\+/;

除了字母、数字和空白,任何字符前都可以加反斜线,不会改变该正则表达式的原意。

2. Testing for matches

console.log(/abc/.test("abcde"));// → trueconsole.log(/abc/.test("abxde"));// → false
字符串中任意位置出现abc序列,都会返回true。

3. Matching a set of characters

判断字符串中是否还有数字:

console.log(/[0123456789]/.test("in 1992"));// → trueconsole.log(/[0-9]/.test("in 1992"));// → true
有一些特殊序列可以代表字符集合:

\d : 任意数字

\w : 字母或数字

\s : 空白(空格、tab、换行等)

\D : 不是数字的任意字符

\W : 不是字母或数字的任意字符

\S : 不是空白的任意字符

. : 不是换行(\n) 的任意字符

匹配日期和时间:30-01-2013 15:20

var dateTime = /\d\d-\d\d-\d\d\d\d \d\d:\d\d/;console.log(dateTime.test("30-01-2003 15:20"));// → trueconsole.log(dateTime.test("30-jan-2003 15:20"));// → false
太多的反斜杠,制造了背景噪声,导致真实模式不容易识别。后面会讲更简洁的写法。

方括弧包含字符集合,[\d.] 表示任意数字或者圆点,在方括弧里,圆点不再具有特殊意义,就代表圆点本身(+ 也是)。

反转字符 ^ 

var notBinary = /[^01]/;console.log(notBinary.test("1100100010100110"));// → falseconsole.log(notBinary.test("1100100010200110"));// → true

4. Repeating parts of a pattern

+ : 一个或多个

/'\d+'/.test("'123'");/'\d+'/.test("''");
* : 0个或多个

/'\d*'/.test("'123'");/'\d*'/.test("''");
? : 0个或1个

/neighbou?r/.test('neighbour');/neighbou?r/.test('neighbor');

{n} : 重复n次

{n, m} : 最少重复n次,最多重复m次

{n,} : 至少重复n次,多则不限

var dateRegex = /\d{4}-\d{1,2}-\d{1,2}/;dateRegex.test("2017-2-22");dateRegex.test("2017-02-22");dateRegex.test("2017-002-02");

5. Grouping subexpressions

var cartoonCrying = /boo+(hoo+)+/i;console.log(cartoonCrying.test("Boohoooohoohooo"));// → true

圆括号用来分组,上面的表达式中,第一个 + 应用于boo的第二个o,第二个 + 应用于hoo的第二个o,第三个 + 应用于 (hoo+) 。

最后的 i 表示不区分大小写。

6. Matches and groups

exec方法

var match = /\d+/.exec("one two 100");console.log(match[0]);  //匹配的字符串: "100"console.log(match.index);  // 匹配的字符串在输入字符串的位置:8console.log(match.input);  // 输入的字符串 "one two 100"
RegExp有一个exec方法,返回的match对象是个字符串数组,另外有两个属性:index, input。

注意,该方法找到第一个匹配就会返回。

match方法

String 对象有个match方法,和RegExp对象的exec方法相同,返回值也完全一样。

var match = "one two 100".match(/\d+/);console.log(match[0]);  //匹配的字符串: "100"console.log(match.index);  // 匹配的字符串在输入字符串的位置:8console.log(match.input);  // 输入的字符串 "one two 100"

如果RegExp中有圆括号包含的分组,则match返回值中会包含各个分组的匹配字符串。

var match = /(\d+)s/.exec("one two 100s");

match[0] : “100s"

match[1]: "100"

如果RegExp中的分组没有匹配,则在返回值中,它的位置是undefined

var match = /bad(ly)?/.exec("bad");
match[0] : "bad"

match[1] : undefined

如果RegExp中的分组匹配多次,则只返回最后一个

var match = /(\d)+/.exec("123") 

match[0] : "123"

match[1]: "3"

7. Date

当前日期与时间

var now = new Date();


2009年12月9日零时

var d = new Date(2009, 11, 9); // 注意:月份从零开始计数,日期从1开始计数


可以指定时、分、秒、毫秒

d = new Date(2009, 11, 9, 12, 59, 59, 999);

d.getTime(); // 得到从1970年开始的毫秒数


可以用毫秒数构造一个Date

new Date(1387407600000);


一堆方法,得到年月日、时分秒等等

getFullYear() , getYear(), getMonth(), getDate(), getHours(), getMinutes(), getSeconds()


用RegExp的exec()方法,抓取日期

function findDate(string) {    var dateTime = /(\d{4})-(\d{1,2})-(\d{1,2})/;    var match = dateTime.exec(string);    return new Date(Number(match[1]),                    Number(match[2]) -1,                    Number(match[3]));}findDate("2003-1-30"));// ▹ Sun Mar 02 2003 00:00:00 GMT+0100 (CET)

8. Word and string boundaries

匹配字符串开头:^

/^!/.test('!asd');//-> true/^a/.test('!asd');//-> false

^ 必须放在第一个字符,否则不能匹配任何东西,例如:/x^/

匹配字符串结尾

/^\d+$/.test('1235');//-> true/^\d+$/.exec('123m');//-> false

匹配word边界

/cat/.test("concatenate");//-> true/\bcat\b/.test("concatenate")//-> false/\bcat\b/.test('dog like cat')//-> true

9. Choice patterns

| 用来提供多种选择

var animalCount = /\b\d+ (pig|cow|chicken)s?\b/;animalCount.test("15 pigs"); // ▹ trueanimalCount.test("15 pigchickens"); // ▹ false

10. The mechanics of matching

var animalCount = /\b\d+ (pig|cow|chicken)s?\b/;

这个RegExp可以画成如下流程图。

当给定一个字符串去匹配这个RegExp时,会按照前后顺序,逐段匹配,第一段匹配成功才会往下找第二段,以此类推。中间有任何一段无法匹配,则过程结束。

对于多项选择 (pig|cow|chicken) 会按照图上从上到下的优先顺序匹配。

11. Backtracking

/\b([01]+b|\d+|[\da-f]+h)\b/

这是一个匹配二进制数/十进制数/十六进制数的RegExp. 流程图如下:


如果给定字符串: "103" , 则先去尝试匹配二进制数,当看到3,无法匹配b,则回溯到1的位置,尝试匹配第二个分支 —— 十进制数。

在RegExp的匹配过程中,每当开始尝试匹配图中的一个分支,都会保存字符串在该点的index,如果遇到无法匹配的情况,就会回溯到这个index。

重复模式的回溯

看这个例子:

/^.*x/.test("abcxe");
首先,.* 会尝试匹配整个字符串 "abcxe" ,然后,它会发现无法匹配x,然后,它一个字符一个字符的回溯,直到匹配上 "abcx" 。

再看一个例子:
匹配二进制数据: /[01]+b/
如果不小心写成这个样子: /([01]+)+b/
匹配结果也是对的。但可能匹配过程会比较复杂,效率低下。看一下它的流程图:

如果去匹配一个尝尝的01串,但最后没有b,它会从最后一个字符一个一个的回溯,每个字符都会回溯内外两层,所以这种写法多了一倍的回溯。

.... 还有一堆内容,后面再写一篇笔记吧。



原创粉丝点击