logo头像

孙宇

javascript 面向对象:7

本文于969天之前发表,文中内容可能已经过时。

  1. 正则表达式
    regular expression
    一个有规则的表达式

    简单的说 他就是一个用于 查找的通配符

    book
    bok
    bouk

    b*k 或 b?k

    将以 b 开头, 以 k 结尾的单词 全部列出来

正则表达式就是 一个用于查找的 含有 匹配字符串 或 匹配元字符的 字符串


"123"
"abc"

"\\d"  一个数字( 0 ~ 9 )
  1. 正则表达式对象
    js 正则表达式对象 就是 由 正则表达式创建的对象, 该对象可以进行 匹配, 提取 和 替换.

    创建正则表达式对象
    1) 构造函数

    var regex = new RegExp( 正则表达式字符串[, 匹配模式] );
    

    2) 字面量

    var regex = /正则表达式/;
    
  2. 使用正则表达式进行匹配
    语法:

    正则对象.test( 字符串 ) -> bool
    

    如果参数字符串中含有 复合 正则匹配的 子字符串, 就返回 true, 否则返回 false

    例如: 查询一段文字中是否包含 itcast

  1. 基本元字符
    1> . 表示任一个非换行的字符

    案例: foot    _ 是 food, foot    写成 foo.
    

    2> () 表示分组和提高优先级
    3> [] 表示一个字符, 出现在 [] 中的字符

    用法: [abc]    出现 [] 中的任意一个字符
    匹配 a, 或 b, 或 c
    foo[dt]
    

    4> | 或

    用法:    正则表达式|正则表达式
    foot 或 food
    foot|food
    foo(t|d)
    

    扩展:

    .         任意的一个字符. 没有任何限制
    []        是出现在[]中的一个字符. 认为 . 的限制级版本
            [abc]: a 或者 b 或者 c
    |        可以认为是 允许使用多个字符的 匹配
            a|b|c
            aa|bb|cc
    

    转义字符: \

    表示点:   \.
    表示[]:   \[  \]
    表示():      \(  \)
    表示\ :   \\
    
  2. 限定元字符
    1> * 紧跟前面的一个字符或一组字符出现 0 次到多次

    表示: 123333333 后面很多 3
    正则: 1233*
          123                     0 次
          1233                     1 次
          12333                 2 次
          ...
          1233333333333333333
    
    1(23)*
    表示:
        1                         0 次
        123                     1 次
        12323                     2 次
        1232323                    3 次
    

    2> + 紧跟在前面的字符出现 1 次到多次

    字符串: 123333333
    正则:   123+
            123
            1233
            12333
    

    3> ? 紧跟在前面的字符出现 0 次或 1 次

    在一段字符串中检查是否含有 http 协议的字符串或 https 协议的字符串
        http://.+|https://.+
        https?://.+
    

    4 {数字} 紧跟在前面的字符出现指定次数

    a{3}    aaa
    

    5 {数字,} 紧跟在前面的字符至少出现指定次数

    a{3,}    aaa, aaaaaaaaa, aaaaaaaaaaaaaa, ...
    

    6 {数字, 数字} 紧跟在前面的字符出现的次数范围

    a{1, 3}        a, aa, aaa
    
  3. 首尾正则表达式
    ^ 表示必须以 xxx 开头

    ^a        必须以 a 开头的字符串
    a         表示一个字符串中只要含有 a 就可以匹配
    
    ^a^a    非法的写法, ^ 如果是表示开头必须写在开头, 而且只能写一个
    

    $ 表示 必须以 xxx 结尾

    a$        必须以 a 结尾
    

    分析 ^a+$

  4. 案例
    1> 写一个正则表达式匹配 身份证号码

    身份证是 18 位数字
    省 市 区 出生年月 随机编码X
    1) 首先是要做匹配, 就一定要使用 ^ $
    2) 是 18 位数字( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ). 可以使用 [0123456789]
        还可以使用 0|1|2|3|4|5|6|7|8|9
    3) 要求是 18 位. 限定 18 位, 即 {18}
    
    组合: ^[0123456789]{18}$
    
    如果最后一位是x
    前面 17 位数字: ^[0123456789]{17}$
    后面要么是数字: [0123456789]
    要么是 x: x
    写法:     [0123456789x]
            [0123456789]|x
            0|1|2|3|4|5|6|7|8|9|x
    
    ^[0123456789]{17}[0123456789x]$
    

    2> 匹配邮箱

    12345678901@qq.com
    abcdefg@126.com
    abcdefg@163.com
    abc@yahoo.com.cn
    .cc
    .org
    .edu
    .中文
    ...
    
    名字 @ 主机名
    
    1) 是要验证邮箱, 那么就需要使用 ^ $
    2) 名字:
        数字与字母
        [0123456789]
        [abcdefghi...]
        [ABCDEFG...]
    
        [] 里面的字符如果是编码序号连续的可以使用连字符连接
        数字: [0-9]  
              [9-0] 错误的, 编码逆序
        字母: [a-z]
              [A-Z]
        整合: [0-9a-zA-Z]
    
        名字的变式方法: [0-9a-zA-Z]+
    3) 主机名
        主机名也是一串字符串或数字
        但是它多了一个 .com .cn
    
    3.1) 只有名字     [0-9a-zA-Z]+
    
    3.2) 只含有一个 .什么
        开始 \.
        中间 [0-9a-zA-Z]+
        只含有一个名字: \.[0-9a-zA-Z]+
    
    3.3) 含有多个名字
        .com.con.cc.c1.c2.c3
        即 .什么 出现一次到多次
    
        (\.[0-9a-zA-Z]+)+
    
    最后主机名可以写成
        [0-9a-zA-Z]+(\.[0-9a-zA-Z]+)+
    

    最后整合一下

    ^[0-9a-zA-Z]+@[0-9a-zA-Z]+(\.[0-9a-zA-Z]+)+$
    
  5. 匹配一个数字
    1> 匹配一个数字

    [0-9]+
    1) 由于是匹配, 包含 ^ $
    2) 首先第一个字符不允许是 0, 所以第一个可以写成 [1-9]
    3) 后面的数字就是 [0-9]
    4) 要求后面的数字出现 0 次到多次, 以匹配任意的 非 0 数字: [1-9][0-9]*
    5) 由于还需要考虑 0, 因此写成 [1-9][0-9]*|0
    6) 考虑 | 优先级最低: ^([1-9][0-9]*|0)$
    
    ^(-?[1-9][0-9]*|0)$
    
2> 匹配一个指定范围的数字
    匹配 0 ~ 255 为例
    [0-255]        0, 1, 2, 5        错误的

    如果要匹配指定范围的数字, 那么需要将字符串结构进行分类
    1) 0 要匹配的, 所以在正则表达式中有 0 这一项
    2) 任意的 2 位数, 即 [1-9][0-9]
    3) 任意的 1 位数, 即 [0-9], 可以将 第 1) 结论合并
    4) 考虑 3 位数的时候, 只允许出现 1xx 的任意数, 而 2xx 的有限制
        因此在分组, 考虑 1xx 的任意数, 可以写成: 1[0-9][0-9]
    5) 考虑 2xx 的数字, 在 200 到 250 之间允许任意取. 所以
        写成: 2[0-4][0-9]
    6) 考虑 250 到 255, 写成 25[0-5]

    综合一起:
        ^([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$

    匹配赢 IPv4 
        127.0.0.1
        192.168.1.1
    ^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]))$

3> 匹配小数
    要求, 小数不允许以 0 结尾
    3.1415
    [0-9]*[1-9]

    ^((-?[1-9][0-9]*|0)(\.[0-9]*[1-9])?)$

    (aaa)?    这个内容出现或不出现
    (aaa|)    也是表达aaa可出现可不出现
    ^((-?[1-9][0-9]*|0)(\.[0-9]*[1-9]|))$

    jq 中有一属性过滤选择器

    [value=name] [value] [value !=name] ...
    了解
    \[[a-zA-Z]((!|\||~|^|$|)=...|)\]
  1. 简写元字符
    \s 空白字符, 包括空格, tab, 回车换行等
    \S 非空白字符

    js 中常常使用 [\s\S] 表示任意字符

\w    表示字符, 包含字母, 数字, 下划线. 
\W  非字符


\d  数字
\D     非数字
  1. 提取
    使用正则表达式可以进行匹配, 使用 exec 可以将匹配到的数据提取出来

    语法:

    正则表达式对象.exec( 字符串 ) -> 封装成数组
    

    案例: 在 ‘abc123def456ghij789klum’ 提取数字

  1. 循环提取
    在一个字符串中将所有复合的要求的字符串提取出来
    1> 正则表达式需要使用全局模式

    var r = new RegExp( '正则', 'g' );
    var r = /正则/g;
    

    2> 调用 exec 首先获得第一个匹配项

    再调用一次该方法, 就可以获得 第二个匹配项
    一直调用下去, 就可以得到所有的匹配项
    直到最后全部匹配完, 如果还用该方法, 则返回 null
    

    案例: 在 ‘abc123def456ghij789klum’ 提取数字

    var r = /\d+/g;
    
    r.exec( str )            => 123
    r.exec( str )            => 456
    r.exec( str )            => 789
    r.exec( str )            => null
    
    while ( res = r.exec( str ) ) {
        // 操作 res, 处理捕获的结果
    }
    
  1. 将匹配到的结果进行解析
    假如有一个字符串: itcast@itcast.cn
    匹配提取邮箱, 同时将邮箱地址部分的名字和主机名都提取出来

    案例:
    var str = ‘我有一个邮箱, 是 itcast@itcast.cn, 还有 abc@126.com, 和 1234567@qq.com’
    要求将里面的邮箱全部提取出来, 然后将名字还有主机名也取出来

// 循环提取的正则表达式
var r = /[a-zA-Z\d]+@[a-zA-Z\d]+(\.[a-zA-Z\d]+)+/g;

// 如果需要将匹配到的结果再次分解, 可以使用分组的形式, 在正则中分组即可

var r = /([a-zA-Z\d]+)@([a-zA-Z\d]+(\.[a-zA-Z\d]+)+)/g;

// 注意, 正则表达式中, 分组是有编号的. 从左往右数 '('. 从 1 开始依次编号
// 匹配提取的结果中, 对应的编号就可以获得分解的数据
  1. 匹配但是不去捕获的元字符
    (?:其他正则表达式内容)

  2. 要截取一个字符串中的一个 html 标签
    var str = ‘123

    456
    7890’;

    1> 要截取 html 标签, 标签使用 <>. 因此正则表达式写成 <\w+>
    2> 与之匹配的标签名是什么?

    如果在一个正则表达式中使用组匹配到某一个数据, 允许在该正则表达式中使用
    '\数字' 的方式引用该组
    
    <(\w+)>.*<\/\1>
    
  3. 贪婪模式
    凡是在正则表达式中, 涉及到次数限定的, 一般默认都是尽可能的多匹配.

    取消贪婪模式. 在次数限定符后面加上 ?

    注意: 贪婪模式性能会略高于非贪婪模式, 所以开发的时候. 一般不考虑贪婪的问题

    只有代码匹配结果出现问题了, 一般一次多匹配了, 才会取消贪婪
    

    多个贪婪在一起的时候的强度

    \d+\d+\d+

    1234567

    如果取消贪婪模式

    \d+?\d+\d+

  4. 否定元字符
    语法:

    [^字符]
    

    不为这些字符的字符

    [^abc] 不是 a 也不是 b 也不是 c 的字符

  1. 字符串的替换
    语法:

    字符串.replace( 查找字符串, 替换字符串 ) -> 字符串
    

    1> 字符串替换方法

    字符串1.replace( 字符串2, 字符串3 )
    在 字符串1 中找到 字符串2, 将其替换成 字符串3, 返回替换后的字符串
    特点: 只替换第一个找到的字符串
    
    "aaa".replace( 'a', 'A' ) -> 'Aaa'
    

    2> 正则替换

    字符串.replace( 正则表达式, 字符串 ) -> 字符串
    
    1. 简单替换
        'aaaaa-------bbbbbb------ccccc'.replace( /-+/, '-' )
        'aaaaa-------bbbbbb------ccccc'.replace( /-+/g, '-' )
    2. 分组替换
        可以在替换字符串中, 使用 $数字 来引用替换的数据
    
        'abc123'.replace( /(\d+)/, 'd$1' ) -> 'abcd123'
    
        '1991-1-1'
        中国: 1991年1月1日
        欧洲: 1/1/1991
        ... : 1991 1 1
    
        '1991-1-19'.replace( /(\d+)-(\d+)-(\d+)/, '$1年$2月$3日' )
    

    3> 函数参数用法(了解)

    语法:
        字符串.replace( 正则表达式, fn )
    
    '我的邮箱是:abc@itcast.cn, 你的邮箱是: defghijk@itcast.cn'
        .replace( /\w+@\w+(\.\w+)+/g, '*' );
    
    '我的邮箱是:abc@itcast.cn, 你的邮箱是: def@itcast.cn'
        .replace( /(\w+)@(\w+(\.\w+)+)/g, function ( s, g1, g2, g3 ) {
            return '*';
        } );
    
    // 要求 只显示 第一个字符, 其余的都是用 * 表示
    '我的邮箱是:abc@itcast.cn, 你的邮箱是: defghijklim@itcast.cn'
        .replace( /(\w+)@(\w+(\.\w+)+)/g, function ( s, g1, g2, g3 ) {
    
            // 将用户名 变成 a***** 的形式
            var first = g1.charAt( 0 );
            var start = [];
            for ( var i = 0; i < g1.length - 1; i++ ) {
                start.push( '*' );
            }
    
            return first + start.join('') + '@' + g2;
    
        } );