• 【Python百日进阶-Web开发-Feffery】Day398 -“一起Dash”训练营Lesson-08_利用fac构建表单(下)、re正则表达式


    前言:fac是什么?

    • feffery-antd-components(简称fac),是国内大佬费弗里(Feffery)老师基于著名的React UI组件库ant design进行二次开发,将ant design中的诸多实用组件及特性引入Dash,帮助开发者使用极低的纯Python代码量,即可快速开发出现代化的交互式web应用,将你有关web应用的美好憧憬✨高效地实现。
      在这里插入图片描述

    • 作为一个开源项目,任何人都可以以任何形式,免费使用它,来打造你心中理想的web应用。

    • 目前fac处于快速迭代期,更多更新的功能请移步官网:

    • 我(岳涛@心馨电脑)在CSDN发布的fac系列学习笔记得到了费弗里(Feffery)老师本人的许可。为了方便更多的fac初学者入门,我把官网的示例代码片段扩充成一个个完整的小项目,适当添加了注释或补充,拿来即用。通过学习fac,我的个人体会是:如果你不是前端开发工程师,暂时不想或没有时间深入前端技术的学习,fac比Vue更适合你。

    “人生苦短,我用Python;Web开发,首选Feffery!”


    ↓↓↓ 今日笔记 ↓↓↓

    一、页面效果

    在这里插入图片描述

    二、项目源码

    import dash
    import re
    from dash import html, dcc
    import feffery_antd_components as fac
    from dash.dependencies import Input, Output, State
    
    app = dash.Dash(__name__)
    
    app.layout = html.Div(
        [
            # 注册窗口
            html.Div(
                [
                    # 标题
                    html.Div(
                        fac.AntdTitle('欢迎注册XX平台', level=2),
                        style={
                            'textAlign': 'center',
                            'marginBottom': '3rem'
                        }
                    ),
    
                    # 表体
                    html.Div(
                        [
                            fac.AntdForm(
                                [
                                    fac.AntdFormItem(
                                        fac.AntdInput(
                                            id='username',
                                            placeholder='用户名可以是英文字母、数字或汉字及其组合。'
                                        ),
                                        id='username-item',
                                        label='用户名',
                                        required=True,
                                        tooltip='用户名可以是英文字母、数字或汉字及其组合。',
                                        style={
                                            'marginBottom': '2rem'
                                        }
                                    ),
                                    fac.AntdFormItem(
                                        fac.AntdInput(
                                            id='email',
                                            placeholder='请输入您的邮箱。'
                                        ),
                                        id='email-item',
                                        label='邮箱',
                                        required=True,
                                        style={
                                            'marginBottom': '2rem'
                                        }
                                    ),
                                    fac.AntdFormItem(
                                        fac.AntdInput(
                                            id='password',
                                            placeholder='请输入密码。',
                                            mode='password'
                                        ),
                                        id='password-item',
                                        label='密码',
                                        required=True,
                                        style={
                                            'marginBottom': '2rem'
                                        }
                                    ),
                                    fac.AntdFormItem(
                                        fac.AntdInput(
                                            id='confirm-password',
                                            placeholder='请再次输入密码。',
                                            mode='password'
                                        ),
                                        id='confirm-password-item',
                                        label='确认密码',
                                        required=True,
                                        style={
                                            'marginBottom': '2rem'
                                        }
                                    ),
                                    fac.AntdFormItem(
                                        fac.AntdDatePicker(
                                            id='birthday',
                                            placeholder='请输入您的出生日期。'
                                        ),
                                        id='birthday-item',
                                        label='出生日期',
                                        style={
                                            'marginBottom': '2rem'
                                        }
                                    ),
                                    fac.AntdFormItem(
                                        fac.AntdButton(
                                            '提交注册',
                                            id='submit',
                                            type='primary',
                                            size='large'
                                        ),
                                        wrapperCol={
                                            'offset': 4
                                        }
                                    )
                                ],
                                wrapperCol={
                                    'span': 20
                                },
                                labelCol={
                                    'span': 4
                                },
                            )
                        ],
                        style={
                            'padding': '3rem',
                        }
                    )
                ],
                style={
                    'width': '50rem',
                    'height': '40rem',
                    'position': 'fixed',
                    'top': '10rem',
                    'left': '20rem',
                    'borderRadius': '2rem',
                    'boxShadow': '0 0.5rem 1rem rgb(150,150,150)',
                    'padding': '3rem'
                }
            )
        ],
        style={
            'padding': '20px',
            'margin': '20px',
        }
    )
    
    
    # 点击提交注册按钮后利用正则表达式验证邮箱
    @app.callback(
        [Output('email-item', 'help'),
         Output('email-item', 'validateStatus')],
        [Input('email', 'value'),
         Input('submit', 'nClicks')],
        # prevent_initial_call=True
    )
    def verify_username(email, nClicks):
        if nClicks:
            if not email:
                return [
                    '邮箱不可为空!',
                    'error'
                ]
            else:
                # 定义邮箱验证规则
                re_mail = r'^[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+){0,4}@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+){0,4}$'
                if not re.match(re_mail, email):
                    return [
                        '请输入合法邮箱!',
                        'error'
                    ]
                else:
                    return [
                        None,
                        None
                    ]
        return dash.no_update
    
    
    # 点击提交注册按钮后利用正则表达式验证用户名
    @app.callback(
        [Output('username-item', 'help'),
         Output('username-item', 'validateStatus')],
        [Input('username', 'value'),
         Input('submit', 'nClicks')],
        # prevent_initial_call=True
    )
    def verify_username(username, nClicks):
        if nClicks:
            if not username:
                return [
                    '用户名不可为空!',
                    'error'
                ]
            else:
                # 在用户名中提取字母数字和汉字
                re_username = re.sub(u"([^\u4e00-\u9fa5\u0030-\u0039\u0041-\u005a\u0061-\u007a])", "", username)
                if not username == re_username:
                    return [
                        '用户名中只能包含:字母、数字和汉字,不能有其他字符!',
                        'error'
                    ]
                else:
                    return [
                        None,
                        None
                    ]
        return dash.no_update
    
    
    # 密码验证
    @app.callback(
        [Output('password-item', 'help'),
         Output('password-item', 'validateStatus'),
         Output('confirm-password-item', 'help'),
         Output('confirm-password-item', 'validateStatus')],
        [Input('password', 'value'),
         Input('confirm-password', 'value'),
         Input('submit', 'nClicks')],
        # prevent_initial_call=True
    )
    def verify_password(password, confirm_password, nClicks):
        # 用户没有点击提交注册按钮,仅验证密码和确认密码是否一致
        if password and confirm_password:
            if password == confirm_password:
                return [
                    None,
                    None,
                    '密码一致!',
                    'success'
                ]
            else:
                return [
                    None,
                    None,
                    '两次输入的密码不一致,请重新输入!',
                    'error'
                ]
        # 用户点击了提交注册按钮
        if nClicks:
            if not password:
                return [
                    '密码不可为空!',
                    'error',
                    None,
                    None
                ]
            elif not confirm_password:
                return [
                    None,
                    None,
                    '确认密码不可为空!',
                    'error',
                ]
            elif not password == confirm_password:
                return [
                    None,
                    None,
                    '两次输入的密码不一致,请重新输入!',
                    'error'
                ]
            elif password == confirm_password:
                return [
                    None,
                    None,
                    '密码一致!',
                    'success'
                ]
    
        return dash.no_update
    
    
    if __name__ == '__main__':
        app.run_server(debug=True)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260

    三、相关知识点:正则表达式

    3.1 正则表达式是什么?

    • 正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。
    • Python 自1.5版本起增加了re 模块,它提供 Perl 风格的正则表达式模式。
    • re 模块使 Python 语言拥有全部的正则表达式功能。
    • compile 函数根据一个模式字符串和可选的标志参数生成一个正则表达式对象。该对象拥有一系列方法用于正则表达式匹配和替换。
    • re 模块也提供了与这些方法功能完全一致的函数,这些函数使用一个模式字符串做为它们的第一个参数。
    • python中的正则表达式大致分为以下几部分:
      • 元字符
      • 模式
      • 函数

    3.2 正则表达式的元字符

    元字符匹配内容
    .匹配任意字符(不包括换行符)
    ^匹配开始位置,多行模式下匹配每一行的开始
    $匹配结束位置,多行模式下匹配每一行的结束
    • |               匹配前一个元字符0到多次
      
      • 1
    • |               匹配前一个元字符1到多次
      
      • 1

    ? | 匹配前一个元字符0到1次
    {m,n} | 匹配前一个元字符m到n次
    \ | 转义字符,跟在其后的字符将失去作为特殊元字符的含义,例如\.只能匹配.,不能再匹配任意字符
    [] | 字符集,一个字符的集合,可匹配其中任意一个字符
    | | 逻辑表达式 或 ,比如 a|b 代表可匹配 a 或者 b
    (…) | 分组,默认为捕获,即被分组的内容可以被单独取出,默认每个分组有个索引,从 1 开始,按照"("的顺序决定索引值
    (?iLmsux) | 分组中可以设置模式,iLmsux之中的每个字符代表一个模式,用法参见 模式 I
    (?:…) | 分组的不捕获模式,计算索引时会跳过这个分组
    (?P…) | 分组的命名模式,取此分组中的内容时可以使用索引也可以使用name
    (?P=name) | 分组的引用模式,可在同一个正则表达式用引用前面命名过的正则
    (?#…) | 注释,不影响正则表达式其它部分,用法参见 模式 I
    (?=…) | 顺序肯定环视,表示所在位置右侧能够匹配括号内正则
    (?!..) | 顺序否定环视,表示所在位置右侧不能匹配括号内正则
    (?<=…) | 逆序肯定环视,表示所在位置左侧能够匹配括号内正则
    (?<!..) | 逆序否定环视,表示所在位置左侧不能匹配括号内正则
    (?(id/name)yes|no) | 若前面指定id或name的分区匹配成功则执行yes处的正则,否则执行no处的正则
    \number | 匹配和前面索引为number的分组捕获到的内容一样的字符串
    \A | 匹配字符串开始位置,忽略多行模式
    \Z | 匹配字符串结束位置,忽略多行模式
    \b | 匹配位于单词开始或结束位置的空字符串
    \B | 匹配不位于单词开始或结束位置的空字符串
    \d | 匹配一个数字, 相当于 [0-9]
    \D | 匹配非数字,相当于 [^0-9]
    \s | 匹配任意空白字符, 相当于 [ \t\n\r\f\v]
    \S | 匹配非空白字符,相当于 [^ \t\n\r\f\v]
    \w | 匹配数字、字母、下划线中任意一个字符, 相当于 [a-zA-Z0-9_]
    \W | 匹配非数字、字母、下划线中的任意字符,相当于 [^a-zA-Z0-9_]

    3.3 常用的正则表达式

    3.3.1 校验数字的表达式

    • 数字:^[0-9]*$
    • n位的数字:^\d{n}$
    • 至少n位的数字:^\d{n,}$
    • m-n位的数字:^\d{m,n}$
    • 零和非零开头的数字:^(0|[1-9][0-9]*)$
    • 非零开头的最多带两位小数的数字:^([1-9][0-9]*)+(.[0-9]{1,2})?$
    • 带1-2位小数的正数或负数:^(\-)?\d+(\.\d{1,2})?$
    • 正数、负数、和小数:^(\-|\+)?\d+(\.\d+)?$
    • 有两位小数的正实数:^[0-9]+(.[0-9]{2})?$
    • 有1~3位小数的正实数:^[0-9]+(.[0-9]{1,3})?$
    • 非零的正整数:^[1-9]\d*$^([1-9][0-9]*){1,3}$^\+?[1-9][0-9]*$
    • 非零的负整数:^\-[1-9][]0-9″*$^-[1-9]\d*$
    • 非负整数:^\d+$^[1-9]\d*|0$
    • 非正整数:^-[1-9]\d*|0$^((-\d+)|(0+))$
    • 非负浮点数:^\d+(\.\d+)?$^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$
    • 非正浮点数:^((-\d+(\.\d+)?)|(0+(\.0+)?))$^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$
    • 正浮点数:^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$
    • 负浮点数:^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$
    • 浮点数:^(-?\d+)(\.\d+)?$^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$

    3.3.2 校验字符的表达式

    • 汉字:^[\u4e00-\u9fa5]{0,}$
    • 英文和数字:^[A-Za-z0-9]+$^[A-Za-z0-9]{4,40}$
    • 长度为3-20的所有字符:^.{3,20}$
    • 由26个英文字母组成的字符串:^[A-Za-z]+$
    • 由26个大写英文字母组成的字符串:^[A-Z]+$
    • 由26个小写英文字母组成的字符串:^[a-z]+$
    • 由数字和26个英文字母组成的字符串:^[A-Za-z0-9]+$
    • 由数字、26个英文字母或者下划线组成的字符串:^\w+$ 或 ^\w{3,20}$
    • 中文、英文、数字包括下划线:^[\u4E00-\u9FA5A-Za-z0-9_]+$
    • 中文、英文、数字但不包括下划线等符号:^[\u4E00-\u9FA5A-Za-z0-9]+$^[\u4E00-\u9FA5A-Za-z0-9]{2,20}$
    • 可以输入含有^%&’,;=?$\”等字符:[^%&',;=?$\x22]+
    • 禁止输入含有~的字符:[^~\x22]+

    3.3.3 殊需求表达式

    • Email地址:^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$
    • 域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?
    • InternetURL:[a-zA-z]+://[^\s]* 或 ^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$
    • 手机号码:^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$
    • 电话号码(“XXX-XXXXXXX”、”XXXX-XXXXXXXX”、”XXX-XXXXXXX”、”XXX-XXXXXXXX”、”XXXXXXX”和”XXXXXXXX):^($$\d{3,4}-)|\d{3.4}-)?\d{7,8}$
    • 国内电话号码(0511-4405222、021-87888822):\d{3}-\d{8}|\d{4}-\d{7}
    • 身份证号(15位、18位数字):^\d{15}|\d{18}$
    • 短身份证号码(数字、字母x结尾):^([0-9]){7,18}(x|X)?$^\d{8,18}|[0-9x]{8,18}|[0-9X]{8,18}?$
    • 帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
    • 密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线):^[a-zA-Z]\w{5,17}$
    • 强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间):^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$
    • 日期格式:^\d{4}-\d{1,2}-\d{1,2}
    • 一年的12个月(01~09和1~12):^(0?[1-9]|1[0-2])$
    • 一个月的31天(01~09和1~31):^((0?[1-9])|((1|2)[0-9])|30|31)$
    • 钱的输入格式:
      有四种钱的表示形式我们可以接受:”10000.00″ 和 “10,000.00″, 和没有 “分” 的 “10000″ 和 “10,000″:^[1-9][0-9]*$
      这表示任意一个不以0开头的数字,但是,这也意味着一个字符”0″不通过,所以我们采用下面的形式:^(0|[1-9][0-9]*)$
      一个0或者一个不以0开头的数字.我们还可以允许开头有一个负号:^(0|-?[1-9][0-9]*)$
      这表示一个0或者一个可能为负的开头不为0的数字.让用户以0开头好了.把负号的也去掉,因为钱总不能是负的吧.下面我们要加的是说明可能的小数部分:^[0-9]+(.[0-9]+)?$
      必须说明的是,小数点后面至少应该有1位数,所以”10.”是不通过的,但是 “10″ 和 “10.2″ 是通过的:^[0-9]+(.[0-9]{2})?$
      这样我们规定小数点后面必须有两位,如果你认为太苛刻了,可以这样:^[0-9]+(.[0-9]{1,2})?$
      这样就允许用户只写一位小数。下面我们该考虑数字中的逗号了,我们可以这样:^[0-9]{1,3}(,[0-9]{3})*(.[0-9]{1,2})?$
      1到3个数字,后面跟着任意个 逗号+3个数字,逗号成为可选,而不是必须:^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$
      备注:这就是最终结果了,别忘了”+”可以用”*”替代。如果你觉得空字符串也可以接受的话(奇怪,为什么?)最后,别忘了在用函数时去掉去掉那个反斜杠,一般的错误都在这里
    • xml文件:^([a-zA-Z]+-?)+[a-zA-Z0-9]+\\.[x|X][m|M][l|L]$
    • 中文字符的正则表达式:[\u4e00-\u9fa5]
    • 双字节字符:[^\x00-\xff] (包括汉字在内,可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1))
    • 空白行的正则表达式:\n\s*\r (可以用来删除空白行)
    • HTML标记的正则表达式:<(\S*?)[^>]*>.*?</\1>|<.*? /> (网上流传的版本太糟糕,上面这个也仅仅能部分,对于复杂的嵌套标记依旧无能为力)
    • 首尾空白字符的正则表达式:^\s*|\s*$(^\s*)|(\s*$) (可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式)
    • 腾讯QQ号:[1-9][0-9]{4,} (腾讯QQ号从10000开始)
    • 中国邮政编码:[1-9]\d{5}(?!\d) (中国邮政编码为6位数字)
    • IP地址:\d+\.\d+\.\d+\.\d+ (提取IP地址时有用)
    • IP地址:((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))

    3.4 正则表达式的模式

    3.4.1 I IGNORECASE,忽略大小写的匹配模式

    import re
    
    text = 'a今b天c周d末e'
    pattern = r'A今b天C周d末E'
    
    print(f'默认匹配:{re.findall(pattern, text)}')
    print(f're.I模式:{re.findall(pattern, text, re.I)}')
    
    # 输出结果:
    默认匹配:[]
    re.I模式:['a今b天c周d末e']
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    s = 'hello World!'
    
    regex = re.compile("hello world!", re.I)
    print regex.match(s).group()
    #output> 'hello World!'
    
    #在正则表达式中指定模式以及注释
    regex = re.compile("(?#注释)(?i)hello world!")
    print regex.match(s).group()
    #output> 'hello World!'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    3.4.2 L LOCALE, 字符集本地化。

    这个功能是为了支持多语言版本的字符集使用环境的,比如在转义符\w,在英文环境下,它代表[a-zA-Z0-9_],即所以英文字符和数字。如果在一个法语环境下使用,缺省设置下,不能匹配"é" 或 “ç”。加上这L选项和就可以匹配了。不过这个对于中文环境似乎没有什么用,它仍然不能匹配中文字符。

    3.4.3 re.M 或 re.MULTILINE,多行模式, 改变 ^ 和 $ 的行为

    import re
    
    text = '今天\n周末!'
    pattern = r'^周末'
    
    print(f'默认匹配:{re.findall(pattern, text)}')
    print(f'多行模式:{re.findall(pattern, text, re.M)}')
    
    # 输出结果
    默认匹配:[]
    多行模式:['周末']
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    s = '''first line
    second line
    third line'''
    
    # ^
    regex_start = re.compile("^\w+")
    print regex_start.findall(s)
    # output> ['first']
    
    regex_start_m = re.compile("^\w+", re.M)
    print regex_start_m.findall(s)
    # output> ['first', 'second', 'third']
    
    #$
    regex_end = re.compile("\w+$")
    print regex_end.findall(s)
    # output> ['line']
    
    regex_end_m = re.compile("\w+$", re.M)
    print regex_end_m.findall(s)
    # output> ['line', 'line', 'line']
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    3.4.4 re.S 或 re.DOTALL,此模式下 ‘.’ 的匹配不受限制,可匹配任何字符,包括换行符

    DOT表示.,ALL表示所有,连起来就是.匹配所有,包括换行符\n。默认模式下.是不能匹配行符\n的。

    import re
    
    text = 'a今\nb天\nc周\nd末\ne!'
    pattern = r'.+'
    
    print(f'默认匹配:{re.findall(pattern, text)}')
    print(f're.S模式:{re.findall(pattern, text, re.S)}')
    # 输出结果
    默认匹配:['a今', 'b天', 'c周', 'd末', 'e!']
    re.S模式:['a今\nb天\nc周\nd末\ne!']
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    s = '''first line
    second line
    third line'''
    #
    regex = re.compile(".+")
    print regex.findall(s)
    # output> ['first line', 'second line', 'third line']
    
    # re.S
    regex_dotall = re.compile(".+", re.S)
    print regex_dotall.findall(s)
    # output> ['first line\nsecond line\nthird line']
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    3.4.5 re.X 或 re.VERBOSE,冗余模式, 此模式忽略正则表达式中的空白和#号的注释,

    例如写一个匹配邮箱的正则表达式

    email_regex = re.compile("[\w+\.]+@[a-zA-Z\d]+\.(com|cn)")
    
    email_regex = re.compile("""[\w+\.]+  # 匹配@符前的部分
                                @  # @符
                                [a-zA-Z\d]+  # 邮箱类别
                                \.(com|cn)   # 邮箱后缀  """, re.X)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.4.6 re.U 或 re.UNICODE,使用 \w, \W, \b, \B 这些元字符时将按照 UNICODE 定义的属性.

    3.4.7 re.A 或 re.ASCII ASCII模式

    顾名思义,ASCII表示ASCII码的意思,让 \w, \W, \b, \B, \d, \D, \s 和 \S 只匹配ASCII,而不是Unicode。

    import re
    
    text = 'a今b天c周d末e'
    pattern = r'\w+'
    
    print(f'默认匹配:{re.findall(pattern, text)}')
    print(f'ASCII模式:{re.findall(pattern, text, re.A)}')
    
    # 输出结果:
    默认匹配:['a今b天c周d末e']
    ASCII模式:['a', 'b', 'c', 'd', 'e']
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在默认匹配模式下\w+匹配到了所有字符串,而在ASCII模式下,只匹配到了a、b、c(ASCII编码支持的字符)。
    注意:这只对字符串匹配模式有效,对字节匹配模式无效。

    3.4.8 re.DEBUG 调试模式

    显示编译时的debug信息。

    import re
    
    text = '今天\n周末!'
    pattern = r'^今天'
    
    print(f'默认匹配:{re.findall(pattern, text)}')
    print('----------------')
    print(f'多行模式:{re.findall(pattern, text, re.DEBUG)}')
    
    # 输出结果
    默认匹配:['今天']
    ----------------
    AT AT_BEGINNING
    LITERAL 20170
    LITERAL 22825
    
     0. INFO 4 0b0 2 2 (to 5)
     5: AT BEGINNING
     7. LITERAL 0x4eca ('今')
     9. LITERAL 0x5929 ('天')
    11. SUCCESS
    多行模式:['今天']
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    3.4.9 正则表达式模式的混用

    正则表达式的模式是可以同时使用多个的,在 python 里面使用按位或运算符 | 同时添加多个模式
    re.compile('', re.I|re.M|re.S)

    3.4.10 每个模式在 re 模块中其实就是不同的数字

    print re.I
    # output> 2
    print re.L
    # output> 4
    print re.M
    # output> 8
    print re.S
    # output> 16
    print re.X
    # output> 64
    print re.U
    # output> 32
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    3.4.11 使用建议

    • python的re模块有9个常量
    • 前5个(IGNORECASE、ASCII、DOTALL、MULTILINE、VERBOSE)有用处
    • 两个(LOCALE、UNICODE)官方不建议使用
    • 两个(TEMPLATE、DEBUG)试验性功能,不能依赖。

    3.5 python的re模块中的函数

    re模块有12个函数,分为4类

    3.5.1 查找一个匹配项

    查找并返回一个匹配项的函数有3个:search、match、fullmatch,他们的区别分别是:

    • search: 查找任意位置的匹配项
    • match: 必须从字符串开头匹配
    • fullmatch: 整个字符串与正则完全匹配
      注意:查找 一个匹配项 返回的都是一个匹配对象(Match)。
    import re
    
    target = '周末快乐,a今天\n周末b!'
    pattern = r'周末b'
    
    print(f'search-查找任意位置的匹配项:{re.search(pattern, target).group()}')
    print(f'match-必须从字符串开头匹配:{re.match(pattern, target)}')
    print(f'fullmatch-整个字符串与正则完全匹配:{re.fullmatch(pattern, target)}')
    
    # 输出结果:
    search-查找任意位置的匹配项:周末b
    match-必须从字符串开头匹配:None
    fullmatch-整个字符串与正则完全匹配:None
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    3.5.2 查找多个匹配项

    查找多项函数主要有:findall函数 与 finditer函数:

    • findall: 从字符串任意位置查找,返回一个列表。一般情况使用findall函数基本没啥影响。
    • finditer:从字符串任意位置查找,返回一个迭代器,使用时一点一点生成出来的,内存使用更优。如果可能存在大量的匹配项的话,建议使用。
    import re
    
    target = '周末快乐,a今天\n周末b!'
    pattern = r'周末b'
    
    print(f'findall-从字符串任意位置查找,返回一个列表:{re.findall(pattern, target)}')
    print(f'finditer-从字符串任意位置查找,返回一个迭代器:{re.finditer(pattern, target)}')
    
    # 输出结果
    findall-从字符串任意位置查找,返回一个列表:['周末b']
    finditer-从字符串任意位置查找,返回一个迭代器:<callable_iterator object at 0x00000210F54168C8>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    3.5.3 分割

    re.split(pattern, string, maxsplit=0, flags=0) 
    
    • 1

    用 pattern 分开 string , maxsplit表示最多进行分割次数, flags表示模式,就是上面我们讲解的常量!

    import re
    
    target = '周末快乐,a今天\n周末b!'
    pattern = r','
    
    print(f'split-分割:{re.split(pattern, target)}')
    
    # 输出结果
     split-分割:['周末快乐', 'a今天\n周末b!']
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    str模块也有一个 split函数,在不需要正则支持数据量和数次不多的情况下使用str.split函数更合适,反之则使用re.split函数。

    3.5.4 替换

    替换主要有sub函数 与 subn函数,他们功能类似!

    • sub函数
    re.sub(pattern, repl, string, count=0, flags=0) 
    
    • 1
    repl替换掉string中被pattern匹配的字符, count表示最大替换次数,flags表示正则表达式的常量。
    
    值得注意的是:sub函数中的入参:repl替换内容既可以是字符串,也可以是一个函数哦! 如果repl为函数时,只能有一个入参:Match匹配对象。
    
    • 1
    • 2
    • 3
    • subn函数
    re.subn(pattern, repl, string, count=0, flags=0) 
    
    • 1
    re.subn函数函数与 re.sub函数 功能一致,只不过返回一个元组 (字符串, 替换次数)。
    
    • 1
    import re
    
    target = '周末快乐,a今天\n周末b!'
    pattern = r','
    repl = r'!'
    print(f'sub-替换:{re.sub(pattern, repl, target, count=2, flags=re.IGNORECASE)}')
    print('--------------')
    print(f'subn-替换:{re.subn(pattern, repl, target, count=2, flags=re.IGNORECASE)}')
    
    # 输出结果
    sub-替换:周末快乐!a今天
    周末b!
    --------------
    subn-替换:('周末快乐!a今天\n周末b!', 1)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    3.5.5 编译正则对象

    compile函数 与 template函数 将正则表达式的样式编译为一个 正则表达式对象 (正则对象Pattern),这个对象与re模块有同样的正则函数(后面我们会讲解Pattern正则对象)。
    而template函数 与 compile函数 类似,只不过是增加了我们之前说的re.TEMPLATE 模式。

    3.5.6 其他函数

    • re.escape(pattern) 可以转义正则表达式中具有特殊含义的字符,比如:. 或者 *,它看似非常好用省去了我们自己加转义,但是使用它很容易出现转义错误的问题,所以并不建议使用它转义,而建议大家自己手动转义!
    • re.purge() 函数作用就是清除 正则表达式缓存,

    3.5.7 groups与group

    group和groups是两个不同的函数。

    • group()和group(0)效果一样,用于获取正则表达式匹配到的全部结果,参数默认0;

    • group(num),num为正整数,获取正则表达式匹配结果中相应的第n个括号内的元组;

    • groups(),用于获取正则表达式全部括号内的元组。m.groups() == (m.group(1), m.group(2), …)

    或者m.groups()[0] == m.group(1),m.groups()[1] == m.group(2)

    在这里插入图片描述

  • 相关阅读:
    分布式AKF拆分原则
    [Emeuelc]DC模拟器Flycast按键设置相关研究
    基于粒子群算法改进小波神经网络的时间序列预测,基于pso-ann的回归分析
    糖友可以喝酸奶吗?
    武汉高性能计算大会2022举办,高性能计算生态发展再添新动力
    人工智能技术与自动驾驶,自动驾驶与人工智能
    〖全域运营实战白宝书 - 运营角色认知篇④〗- 与运营打交道的小伙伴
    机器人制作开源方案 | 行星探测车实现云端控制
    <select>表单元素
    笔记55:长短期记忆网络 LSTM
  • 原文地址:https://blog.csdn.net/yuetaope/article/details/123715820