正则表达式 入门

2017-08-14  本文已影响48人  小小小超子

原理

正则引擎

为什么正则能有效,因为有引擎,这和为什么JS能执行一样,有JS引擎

正则的引擎大致可分为两类:DFA和NFA

这里的“确定型”指,对于某个确定字符的输入,这台机器的状态会确定地从a跳到b,“非确定型”指,对于某个确定字符的输入,这台机器可能有好几种状态的跳法;这里的“有穷”指,状态是有限的,可以在有限的步数内确定某个字符串是被接受还是发好人卡的;这里的“自动机”,可以理解为,一旦这台机器的规则设定完成,就可以自行判断了,不要人看。

基础知识

正则眼中的字符串——n个字符,n+1个位置

为什么要有字符还要有位置呢?因为位置是可以被匹配的。

“占有字符”和“零宽度”:

占有字符是互斥的,零宽度是非互斥的。也就是一个字符,同一时间只能由一个子表达式匹配,而一个位置,却可以同时由多个零宽度的子表达式匹配。举个栗子,比如/aa/是匹配不了a的,这个字符串中的a只能由正则的第一个a字符匹配,而不能同时由第二个a匹配(废话);但是位置是可以多个匹配的,比如/\b\ba/是可以匹配a的,虽然正则表达式里有2个表示单词开头位置的\b元字符,这两个\b是可以同时匹配位置0(在这个例子中)的

控制权和传动

控制权是指哪一个正则子表达式(可能为一个普通字符、元字符或元字符序列组成)在匹配字符串,那么控制权就在哪。

传动是指正则引擎的一种机制,传动装置将定位正则从字符串的哪里开始匹配。

正则表达式当开始匹配的时候,一般是由一个子表达式获取控制权,从字符串中的某一个位置开始尝试匹配,一个子表达式开始尝试匹配的位置,是从前一子表达匹配成功的结束位置开始的

语法

要用某类常见字符——简单元字符

要表示出现次数(重复)——限定符

匹配位置——定位符和零宽断言

想表达“或”的意思——字符簇和分歧

字符簇可用来表达字符级别的“或”语义,表示的是方括号中的字符任选一:

想表达“非”的意思——反义

贪婪和非贪婪

在限定符中,除了{n}确切表示重复几次,其余的都是一个有下限的范围。

在默认的模式(贪婪)下,会尽可能多的匹配内容。比如用ab*去匹配字符串“abbb”,结果是“abbb”。

而通过在限定符后面加问号?可以进行非贪婪匹配,会尽可能少地匹配。用ab*?去匹配“abbb”,结果会是“a”。

不带问号的限定符也称匹配优先量词,带问号的限定符也称忽略匹配优先量词。

JS 中的正则

字面量, 构造函数和工厂符号都是可以的:

         /pattern/flags
         new RegExp(pattern [, flags])
         RegExp(pattern [, flags])

参数
pattern
正则表达式的文本。
flags
如果指定,标志可以具有以下值的任意组合:

有两种方法来创建一个RegExp对象:一是字面量、二是构造函数。要指示字符串,字面量的参数不使用引号,而构造函数的参数使用引号。因此,以下表达式创建相同的正则表达式

        /ab+c/i;
        new RegExp('ab+c', 'i');
        new RegExp(/ab+c/, 'i');

方法

RegExp.prototype.exec()

exec() 方法在一个指定字符串中执行一个搜索匹配。返回一个结果数组或 null。

        var matches = /h./.exec('This is a hello world!');
        console.log(matches);        // [ 'hi', index: 1, input: 'This is a hello world!' ]

RegExp.prototype.test()

test() 方法执行一个检索,用来查看正则表达式与指定的字符串是否匹配。返回 true 或 false。

当你想要知道一个模式是否存在于一个字符串中时,就可以使用 test()(类似于 String.prototype.search() 方法),差别在于test返回一个布尔值,而 search 返回索引(如果找到)或者-1(如果没找到)

        let str = 'hello world!';
        let result = /hello/.test(str);
        console.log(result);
        // true

例子

使用正则改变数据结构

下例使用 replace 方法 (继承自 String)去匹配姓名 first last 输出新的格式 last, first。脚本中使用 $1 和 $2 指明括号里先前的匹配.

        var re = /(\w+)\s(\w+)/;
        var str = "John Smith";
        var newstr = str.replace(re, "$2, $1");
        print(newstr);          //"Smith, John"

在多行中使用正则表达式

        var s = "Please yes\nmake my day!";
        s.match(/yes.*day/);
        // Returns null
        s.match(/yes[^]*day/);
        // Returns 'yes\nmake my day'

使用正则表达式和 Unicode 字符

\w 或 \W 只会匹配基本的 ASCII 字符;如 'a' 到 'z'、 'A' 到 'Z'、 0 到 9 及 '_'。为了匹配其他语言中的字符,如西里尔(Cyrillic)或 希伯来语(Hebrew),要使用 \uhhhh,"hhhh" 表示以十六进制表示的字符的 Unicode 值

        var text = "Образец text на русском языке";
        var regex = /[\u0400-\u04FF]+/g;

        var match = regex.exec(text);
        print(match[1]);  // prints "Образец"
        print(regex.lastIndex);  // prints "7"

        var match2 = regex.exec(text);
        print(match2[1]);  // prints "на" [did not print "text"]
        print(regex.lastIndex);  // prints "15"

        // and so on

从 URL 中提取子域名

        var url = "http://xxx.domain.com";
        print(/[^.]+/.exec(url)[0].substr(7)); // prints "xxx"
上一篇 下一篇

猜你喜欢

热点阅读