📓
Study
  • README
  • Application
    • Contest
      • 竞赛trick
  • Basic Know
    • 半监督学习
    • 贝叶斯
      • 朴素贝叶斯分类器
    • 对抗训练
    • 概率图模型
      • CRF
      • HMM
      • 概率图模型
    • 关联分析
    • 归纳偏置
      • [什么是 Inductive bias(归纳偏置)?](BasicKnow/归纳偏置/什么是 Inductive bias(归纳偏置)?.md)
    • 聚类
    • 决策树
    • 绿色深度学习
    • 树模型&集成学习
      • 提升树
      • Ada Boost
      • [集成学习]
    • 特征工程
      • 数据分桶
      • 特征工程概述
      • 特征选择
      • LDA
      • PCA
    • 线性模型
      • 感知机
      • 最大熵模型
      • SVM
        • SVM支持向量机
      • 逻辑回归
      • 线性回归
    • 优化算法
      • 拉格朗日对偶性
      • 牛顿法
        • 牛顿法&拟牛顿法
      • 梯度下降法
        • 梯度下降算法
      • 优化算法
    • 预处理
      • [1-1]正则表达式
      • [1-2]文本预处理
      • [1-3]词性
      • [1-4]语法分析
      • [1-6]文本分类
      • [1-7]网络爬取
      • 【备用】正则表达式
      • 7.re模块
      • 词典匹配
      • 分词
      • 子表达式
      • Todo
    • 主题模型
      • LDA
    • Deep Learning
      • 反向传播
      • 梯度消失&梯度爆炸
      • Batch Size
      • 1.DLbasis
      • 小概念
      • MLstrategy
      • CNN
      • RNN及其应用
      • 关于深度学习实践
      • 神经网络概述
      • Batch Normalization
      • Program CNN
      • Program D Lbasis
      • Program DN Nimprove
      • Program Neural Style Transfer
      • Summer DL
    • EM算法
    • GAN
      • Gans In Action Master
    • GNN
      • 搜广推之GNN
      • Representation Learning
        • Anomalydetection
        • Conclusion
        • Others
        • Papernotes
        • Recommadation
    • k近邻法
      • K近邻
    • Language Model
      • 语言模型解码采样策略
      • [1-1][语言模型]从N-gram模型讲起
      • [1-2][语言模型]NNLM(神经网络语言模型)
      • [1-3][语言模型]基于RNN的语言模型
      • [1-4][语言模型]用N-gram来做完形填空
      • [1-5][语言模型]用KenLM来做完形填空
    • Loss Function
      • 常用损失函数
      • Focal Loss
      • softmax+交叉熵
    • Machine Learning
      • [基础]概念
      • 待整合
      • 交叉验证
      • 无监督学习
      • 优缺点
      • ML Yearning
      • SVD
    • Statistics Math
      • 程序员的数学基础课
      • 数学基础
      • 统计&高数
      • 统计题目
      • 线性代数
      • 组合数学
      • Discrete Choice Model
      • Nested Choice Model
  • Course Note
    • 基于TensorFlow的机器学习速成课程
      • [Key ML Terminology](CourseNote/基于TensorFlow的机器学习速成课程/Key ML Terminology.md)
    • 集训营
      • 任务说明
      • 算法实践1.1模型构建
      • 算法实践1.2模型构建之集成模型
      • 算法实践2.1数据预处理
    • 李宏毅机器学习
      • 10DNN训练Tips
        • Chapter 18
      • 16无监督学习
        • Chapter 25
    • 贪心NLP
      • 贪心NLP笔记
    • Cs 224 N 2019
      • [A Simple But Tough To Beat Baseline For Sentence Embeddings](CourseNote/cs224n2019/A Simple but Tough-to-beat Baseline for Sentence Embeddings.md)
      • [Lecture 01 Introduction And Word Vectors](CourseNote/cs224n2019/Lecture 01 Introduction and Word Vectors.md)
      • [Lecture 02 Word Vectors 2 And Word Senses](CourseNote/cs224n2019/Lecture 02 Word Vectors 2 and Word Senses.md)
      • [Lecture 03 Word Window Classification Neural Networks And Matrix Calculus](CourseNote/cs224n2019/Lecture 03 Word Window Classification, Neural Networks, and Matrix Calculus.md)
      • [Lecture 04 Backpropagation And Computation Graphs](CourseNote/cs224n2019/Lecture 04 Backpropagation and Computation Graphs.md)
      • [Lecture 05 Linguistic Structure Dependency Parsing](CourseNote/cs224n2019/Lecture 05 Linguistic Structure Dependency Parsing.md)
      • [Lecture 06 The Probability Of A Sentence Recurrent Neural Networks And Language Models](CourseNote/cs224n2019/Lecture 06 The probability of a sentence Recurrent Neural Networks and Language Models.md)
      • Stanford NLP
    • Deep Learning Book Goodfellow
      • Books
        • Deep Learning Book Chapter Summaries Master
      • 提纲
      • C 5
      • C 6
      • [Part I Applied Math And Machine Learning Basics](CourseNote/Deep-Learning-Book-Goodfellow/Part I - Applied Math and Machine Learning basics.md)
    • Lihang
    • NLP实战高手课
      • 极客时间_NLP实战高手课
    • 工具&资料
    • 机器学习、深度学习面试知识点汇总
    • 七月kaggle课程
    • 算法工程师
    • 贪心科技机器学习必修知识点特训营
    • 唐宇迪机器学习
    • 语言及工具
    • AI技术内参
    • Suggestions
  • Data Related
    • 数据质量
      • 置信学习
    • 自然语言处理中的数据增广_车万翔
      • 自然语言处理中的数据增广
    • Mixup
    • 数据不均衡问题
    • 数据增强的方法
  • Knowledge Graph
    • Information Extraction
      • 联合抽取
        • PRGC
      • Code
        • BERT微调
      • NER
        • 阅读理解做NER
          • MRC
        • FLAT
        • Global Pointer
        • 命名实体识别NER
    • Keyword Extraction
      • 关键词抽取
    • 小米在知识表示学习的探索与实践
    • KG
  • Multi Task
    • EXT 5
      • Ex T 5
  • NLG
    • Dailogue
      • 比赛
        • 对话评估比赛
          • [simpread-DSTC10 开放领域对话评估比赛冠军方法总结](NLG/Dailogue/比赛/对话评估比赛/simpread-DSTC10 开放领域对话评估比赛冠军方法总结.md)
      • 任务型对话
        • DST
          • DST概述
        • NLG
          • NLG概述
        • NLU
          • NLU概述
        • 任务型对话概述
        • simpread-任务型对话系统预训练最新研究进展
      • 问答型对话
        • 检索式问答
          • 基于预训练模型的检索式对话系统
          • 检索式文本问答
        • 业界分享
          • 低资源场景下的知识图谱表示学习和问答_阿里_李杨
          • QQ浏览器搜索智能问答
        • 问答型对话系统概述
      • 闲聊型对话
        • 闲聊型对话系统概述
      • 业界分享
        • 人工智能与心理咨询
        • 腾讯多轮对话机器人
        • 微软小冰
        • 小布助手闲聊生成式算法
        • 美团智能客服实践_江会星
        • 去哪儿智能客服探索和实践
        • 实时语音对话场景下的算法实践_阿里_陈克寒
        • 智能语音交互中的无效query识别_小米_崔世起
        • UNIT智能对话
      • 主动对话
      • EVA
        • EVA分享
        • EVA模型
      • PLATO
      • RASA
    • Machine Translation
      • 业界分享
        • 爱奇艺台词翻译分享
      • Paper
        • Deep Encoder Shallow Decoder
    • RAGRelated
    • Text 2 SQL
      • M SQL
        • [M SQL 2](NLG/Text2SQL/M-SQL/M-SQL (2).md)
      • [Text2SQL Baseline解析](NLG/Text2SQL/Text2SQL Baseline解析.md)
      • Text 2 SQL
    • Text Summarization
      • [文本摘要][paper]CTRLSUM
      • 文本摘要
  • Pre Training
    • 业界分享
      • 超大语言模型与语言理解_黄民烈
        • 超大语言模型与语言理解
      • 大模型的加速算法_腾讯微信
        • 大模型的加速算法
      • 孟子轻量化预训练模型
      • 悟道文汇文图生成模型
      • 悟道文澜图文多模态大模型
      • 语义驱动可视化内容创造_微软
        • 语义驱动可视化内容创造
    • Base
      • Attention
      • Mask
        • NLP中的Mask
      • Position Encoding
        • 位置编码
    • BERT
      • ALBERT
      • Bert
        • Venv
          • Lib
            • Site Packages
              • idna-3.2.dist-info
                • LICENSE
              • Markdown-3.3.4.dist-info
                • LICENSE
              • Tensorflow
                • Include
                  • External
                    • Libjpeg Turbo
                      • LICENSE
                  • Unsupported
                    • Eigen
                      • CXX 11
                        • Src
                          • Tensor
              • Werkzeug
                • Debug
                  • Shared
                    • ICON LICENSE
        • CONTRIBUTING
        • Multilingual
      • Ro BER Ta
      • BERT
      • BERT面试问答
      • BERT源码解析
      • NSP BERT
    • BERT Flow
    • BERT Zip
      • Distilling The Knowledge In A Neural Network
      • TINYBERT
      • 模型压缩
    • CPM
    • CPT
      • 兼顾理解和生成的中文预训练模型CPT
    • ELECTRA
    • EL Mo
    • ERNIE系列语言模型
    • GPT
    • MBART
    • NEZHA
    • NLG Sum
      • [simpread-预训练时代下的文本生成|模型 & 技巧](Pre-training/NLGSum/simpread-预训练时代下的文本生成|模型 & 技巧.md)
    • Prompt
      • 预训练模型的提示学习方法_刘知远
        • 预训练模型的提示学习方法
    • T 5
      • Unified SKG
      • T 5
    • Transformer
    • Uni LM
    • XL Net
    • 预训练语言模型
    • BERT变种
  • Recsys
    • 多任务Multi-task&推荐
    • 推荐介绍
    • 推荐系统之召回与精排
      • 代码
        • Python
          • Recall
            • Deep Match Master
              • Docs
                • Source
                  • Examples
                  • FAQ
                  • Features
                  • History
                  • Model Methods
                  • Quick Start
    • 业界分享
      • 腾讯基于知识图谱长视频推荐
    • 召回
    • Sparrow Rec Sys
    • 深度学习推荐系统实战
    • 推荐模型
    • Deep FM
  • Search
    • 搜索
    • 业界分享
      • 爱奇艺搜索排序算法实践
      • 语义搜索技术和应用
    • 查询关键字理解
    • 搜索排序
    • BM 25
    • KDD21-淘宝搜索中语义向量检索技术
    • query理解
    • TFIDF
  • Self Supervised Learning
    • Contrastive Learning
      • 业界分享
        • 对比学习在微博内容表示的应用_张俊林
      • Paper
      • R Drop
      • Sim CSE
    • 自监督学习
  • Text Classification
    • [多标签分类(Multi-label Classification)](TextClassification/多标签分类(Multi-label Classification)/多标签分类(Multi-label Classification).md)
    • Fast Text
    • Text CNN
    • 文本分类
  • Text Matching
    • 文本匹配和多轮检索
    • CNN SIM
    • Word Embedding
      • Skip Gram
      • Glove
      • Word 2 Vec
    • 文本匹配概述
  • Tool
    • 埋点
    • 向量检索(Faiss等)
    • Bigdata
      • 大数据基础task1_创建虚拟机+熟悉linux
      • 任务链接
      • Mr
      • Task1参考答案
      • Task2参考答案
      • Task3参考答案
      • Task4参考答案
      • Task5参考答案
    • Docker
    • Elasticsearch
    • Keras
    • Numpy
    • Python
      • 可视化
        • Interactivegraphics
        • Matplotlib
        • Tkinter
        • Turtle
      • 数据类型
        • Datatype
      • python爬虫
        • Python Scraping Master
          • phantomjs-2.1.1-windows
        • Regularexp
        • Scrapying
        • Selenium
      • 代码优化
      • 一行代码
      • 用python进行语言检测
      • Debug
      • Exception
      • [Features Tricks](Tool/python/Features & Tricks.md)
      • Fileprocess
      • Format
      • Functional Programming
      • I Python
      • Magic
      • Math
      • Os
      • Others
      • Pandas
      • Python Datastructure
      • Python操作数据库
      • Streamlit
      • Time
    • Pytorch
      • Dive Into DL Py Torch
        • 02 Softmax And Classification
        • 03 Mlp
        • 04 Underfit Overfit
        • 05 Gradient Vanishing Exploding
        • 06 Text Preprocess
        • 07 Language Model
        • 08 Rnn Basics
        • 09 Machine Translation
        • 10 Attention Seq 2 Seq
        • 11 Transformer
        • 12 Cnn
        • 14 Batchnorm Resnet
        • 15 Convexoptim
        • 16 Gradientdescent
        • 17 Optim Advance
    • Spark
      • Pyspark
        • pyspark之填充缺失的时间数据
      • Spark
    • SQL
      • 数据库
      • Hive Sql
      • MySQL实战45讲
    • Tensor Flow
      • TensorFlow入门
  • Common
  • NLP知识体系
Powered by GitBook
On this page
  • 一、常用函数说明
  • 二、Match对象
  • 三、flags参数
  • 四、re.compile函数
  • 五、其它
  • 参考资料

Was this helpful?

  1. Basic Know
  2. 预处理

7.re模块

re模块是Python的内置模块,无需安装。

re模块的调用方式:import re。

re库默认采用贪婪匹配,即输出匹配最长的子串。

模式和被搜索的字符串既可以是Unicode字符串(str),也可以是8位字节串(bytes)。但是两者不能混用,即不能用一个字节串模式去匹配Unicode字符串,反之亦然。替换操作也是一样的,替换字符串的类型、模式、搜索字符串的类型必须一致。

正则表达式使用反斜杠字符\来进行转义,使得某些特殊字符能够表示其本身的含义。比如.表示匹配除换行符以外的任意字符,\.则表示.本身。

而Python中也会使用反斜杠字符来进行转义,这就可能造成困扰。比如要匹配\,正则表达式可以表示成\\,这里使用反斜杠转移。而在Python里每个反斜杠又必须表示成\\,因此最终的模式字符串就是\\\\。这未免过于复杂。

解决办法是使用Python的原生字符串表示法,在字符串前加'r'。原生字符串中的每个字符都表示它本身的含义。因此r"\n"表示\和n两个字符的字符串,而"\n"则表示一个换行符的字符串。上述反斜杠的模式就可以表示成r"\\"。

一、常用函数说明

(1)re.search(pattern, string, flags=0)

re.search() 在一个字符串中搜索匹配正则表达式的第一个位置。

如果函数匹配成功则会返回一个匹配对象(Match对象,后面会详细说明),否则返回None。

参数说明:pattern是匹配的正则表达式。string是要匹配的字符串。flags是正则表达式使用时的控制标记,后面会详细说明。

函数的用途:可以用来进行数据验证,在正则表达式两端加上\A和\Z,并判断返回值是否为None

例1:验证字符串是否为6位数字

# 数据验证
# ^和$,\A和\Z一般成对出现
re.search(r"\A\d{6}\Z", "123456\n") != None   # False
re.search(r"\A\d{6}\Z", "123456") != None   # True

例2:pep20.txt存储了网页https://www.python.org/dev/peps/pep-0020/的内容,从中提取出网页的标题。标题的格式形如<title>标题内容</title>

先读取文本内容

with open("pep20.txt", "r") as f:
    content = f.read()

用正则表达式来匹配

m = re.search(r"<title>.*?</title>", content)
m.group()
# '<title>PEP 20 -- The Zen of Python | Python.org</title>'

group()方法是取出分组匹配结果,默认为0,表示取出整个匹配结果。这里将标签title及其内容都取出来了,如果我们只想要内容怎么办呢?可以使用子表达式来捕获,然后取出来即可:

m = re.search(r"<title>(.*?)</title>", content)
m.group(1)
# PEP 20 -- The Zen of Python | Python.org

这里取出第一个分组的结果,也就是标题内容。

作业1:验证输入的文本是否为合法的日期格式。规定合法的日期格式为"yyyy-mm-dd"。月份和日期可以不规范写,例如2020-12-2和2020-2-12也是合法的。不考虑日期是否真实存在。要求表达式如果合法返回True,否则返回False。

答案:

re.search(r"^\d{4}-((1[0-2])|(0?[1-9]))-(([1-2][0-9])|(0?[1-9])|(3[0-1]))$", "2020-12-12") != None

作业2:从pep20.txt里取出Python之禅的内容,即:

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

答案:

content[re.search('<pre class="literal-block">', content).end():re.search("</pre>", content).start()]

(2)re.match(pattern, string, flags=0)

re.match() 从一个字符串的起始位置匹配正则表达式,如果不是起始位置匹配成功的话就返回None

参数和re.search的参数一样。

注意即便是 MULTILINE多行模式(多行模式下^会将给定字符串的每行当作匹配开始), re.match() 也只匹配字符串的开始位置,而不匹配每行开始。

这个方法可以用来筛选出我们需要的数据。

例如我们想从pep20.txt内容里找出下面这个表格里的内容(见PEP的页面https://www.python.org/dev/peps/pep-0020/):

PEP:
20

Title:

The Zen of Python

Author:

tim.peters at gmail.com (Tim Peters)

Status:

Active

Type:

Informational

Created:

19-Aug-2004

Post-History:

22-Aug-2004

可以发现上面的内容在一个表格里,相关的html文本是:

<table class="rfc2822 docutils field-list" frame="void" rules="none">\n<col class="field-name"/>\n<col class="field-body"/>\n<tbody valign="top">\n<tr class="field"><th class="field-name">PEP:</th><td class="field-body">20</td>\n</tr>\n<tr class="field"><th class="field-name">Title:</th><td class="field-body">The Zen of Python</td>\n</tr>\n<tr class="field"><th class="field-name">Author:</th><td class="field-body">tim.peters at gmail.com (Tim Peters)</td>\n</tr>\n<tr class="field"><th class="field-name">Status:</th><td class="field-body">Active</td>\n</tr>\n<tr class="field"><th class="field-name">Type:</th><td class="field-body">Informational</td>\n</tr>\n<tr class="field"><th class="field-name">Created:</th><td class="field-body">19-Aug-2004</td>\n</tr>\n<tr class="field"><th class="field-name">Post-History:</th><td class="field-body">22-Aug-2004</td>\n</tr>\n</tbody>\n</table>

我们需要的内容其实都包含在<tr class="field"><th class="field-name">内容1</th><td class="field-body">内容2</td>这样的形式中,且都以换行符分隔。因此在读取文件的时候,可以按行读取,验证每一行是否是我们需要的内容:

with open("pep20.txt", "r") as f:
    lines = f.readlines()
    for line in lines:
        m = re.match('<tr class="field"><th class="field-name">(.*)</th><td class="field-body">(.*)</td>', line)
        # 如果符合要求,则输出
        if m:
            print(m.groups())

输出结果:

('PEP:', '20')
('Title:', 'The Zen of Python')
('Author:', 'tim.peters at gmail.com (Tim Peters)')
('Status:', 'Active')
('Type:', 'Informational')
('Created:', '19-Aug-2004')
('Post-History:', '22-Aug-2004')

(3)re.fullmatch(pattern, string, flags=0)

re.fullmatch()如果整个字符串匹配到正则表达式,就返回一个相应的匹配对象,否则返回None。

这个方法要求字符串和正则表达式完全匹配,如果只是部分匹配则返回None

re.match(r"\d{6}", "1234567") != None   # True
re.fullmatch(r"\d{6}", "1234567") != None   # False
re.fullmatch(r"\d{6}", "123456") != None   # True

re.match()中提取表格内容的例子也可以用re.fullmatch()实现,但是每一行要去掉前后的空格。

with open("pep20.txt", "r") as f:
    lines = f.readlines()
    for line in lines:
        m = re.fullmatch('<tr class="field"><th class="field-name">(.*)</th><td class="field-body">(.*)</td>', line.strip())
        # 如果符合要求,则输出
        if m:
            print(m.groups())

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

re.split() 将一个字符串按照正则表达式匹配结果进行分割,返回列表类型。

maxsplit是分隔次数,例如maxsplit=1表示分隔一次,默认为 0,表示不限制次数。 如果是负数,表示不做任何切分。

例如:

re.split(r'\W+', 'Words, words, words.')
# ['Words', 'words', 'words', '']
re.split(r'(\W+)', 'Words, words, words.')
# ['Words', ', ', 'words', ', ', 'words', '.', '']
re.split(r'\W+', 'Words, words, words.', 1)
# ['Words', 'words, words.']
re.split('[a-f]+', '0a3B9', flags=re.IGNORECASE)  # re.IGNORECASE表示忽略大小写
# ['0', '3', '9']

加上()会使得分割后的列表保留分隔符,不加的话就不会保留。

如果分隔符里有捕获组合,并且匹配到字符串的开始,那么结果将会以一个空字符串开始。对于结尾也是一样

re.split(r'(\W+)', '...words, words...')
# ['', '...', 'words', ', ', 'words', '...', '']

样式的空匹配将分开字符串,但只在不相临的状况生效。

re.split(r'\b', 'Words, words, words.')
# ['', 'Words', ', ', 'words', ', ', 'words', '.']
re.split(r'\W*', '...words...')
# ['', '', 'w', 'o', 'r', 'd', 's', '', '']
re.split(r'(\W*)', '...words...')
# ['', '...', '', '', 'w', '', 'o', '', 'r', '', 'd', '', 's', '...', '', '', '']

作业:以数字和空格(即空格和数字都必须有)作为分隔符分割这句话"我有1只松鼠 2条狗 66只猫 还有鱼7 信不信",使得分割后结果为['我有1只松鼠', '2条狗', '66只猫 还有鱼7', '信不信']

答案:

name = "我有1只松鼠 2条狗  66只猫 还有鱼7 信不信"
re.split('(?<=\d)\s+|\s+(?=\d)', name)
# ['我有1只松鼠', '2条狗', '66只猫 还有鱼7', '信不信']

看到结果是:有空格+数字,或者数字+空格的地方都被分隔开了。且分隔后将空格去掉,数字保留。

(?<=\d)\s+是查找数字后面的空格(可以是多个),\s+(?=\d)是查找数字前面的空格(可以是多个)。

(5)re.findall(pattern, string, flags=0)

re.findall() 搜索字符串,以列表类型返回全部不重复的能匹配的子串。如果样式里存在一到多个组,就返回一个组合列表;就是一个元组的列表(如果样式里有超过一个组合的话)。空匹配也会包含在结果里。

例如寻找文本中出现的所有英文字母:

name = "abc 123 def 456"
re.findall(r"[a-zA-Z]", name)
# ['a', 'b', 'c', 'd', 'e', 'f']

作业1:还是以取出PEP网页的表格内容为例,如何用re.findall()实现呢?

答案:不需要按行读取文本,一行代码搞定:

re.findall('<tr class="field"><th class="field-name">(.*)</th><td class="field-body">(.*)</td>', content)

输出一个列表:

[('PEP:', '20'),
 ('Title:', 'The Zen of Python'),
 ('Author:', 'tim.peters at gmail.com (Tim Peters)'),
 ('Status:', 'Active'),
 ('Type:', 'Informational'),
 ('Created:', '19-Aug-2004'),
 ('Post-History:', '22-Aug-2004')]

作业2:取出PEP网页中所有形如title="xxxx"里的xxxx。注意使用非贪婪匹配。并且过滤xxxx为空的内容不输出。

答案:

[title for title in re.findall('title="(.*?)"', content) if title.strip() != '']

###(6)re.finditer(pattern, string, flags=0)

re.finditer() 搜索字符串,返回一个非重复匹配结果的迭代类型,每个迭代元素是match对象。

例如寻找关键词在文本中出现的所有起始位置:

name = "123123"
keyword = "123"
start_list = [m.start() for m in re.finditer(keyword, name)]
start_list
# [0, 3]

(7)re.sub(pattern, repl, string, count=0, flags=0)

re.sub() 在一个字符串中替换所有匹配正则表达式的子串,返回替换后的字符串

参数说明

  • pattern是匹配的正则表达式

  • repl : 替换的字符串,也可为一个函数。 例如def capitalize(match): return match.group(1).upper+match.group(2).lower()

  • string是要被查找替换的字符串

  • count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。count必须是非负整数。

例如

re.sub(r'def\s+([a-zA-Z_][a-zA-Z_0-9]*)\s*\(\s*\):',
        r'static PyObject*\npy_\1(void)\n{',
        'def myfunc():')
# 'static PyObject*\npy_myfunc(void)\n{'

这里的pattern是匹配一个def函数,将其替换成static PyObject*\npy_\1(void)\n{,这里面的\1是pattern匹配字符串的第一个子表达式,即([a-zA-Z_][a-zA-Z_0-9]*)匹配到的内容,在这里就是myfunc。

再来看一个替换字符串repl为函数的例子:

def dashrepl(matchobj):
    if matchobj.group(0) == '-': return ' '
    else: return '-'
re.sub('-{1,2}', dashrepl, 'pro----gram-files')
# 'pro--gram files'

re.sub(r'\sAND\s', ' & ', 'Baked Beans And Spam', flags=re.IGNORECASE)
# 'Baked Beans & Spam'

-{1,2}匹配到两个--和一个-,通过函数dashrepl将连续的--替换成-,将-替换成空格,因此得到pro--gram files。

第二个例子中,\sAND\s匹配到And及其前后的2个空格,将其替换成' & '。

另外,空匹配只在不相临连续的情况被更替,所以 re.sub('x*', '-', 'abxd') 返回 '-a-b--d-' 。

作业1:在中英文字符之间加上空格

例如文本"今天真开心happy快乐",加上空格后变成"今天真开心 happy 快乐"

答案:

name = "今天真开心happy快乐"
name = re.sub('([A-Za-z]+)([\u4e00-\u9fa5]+)', r'\1 \2', name)
name = re.sub('([\u4e00-\u9fa5]+)([A-Za-z]+)', r'\1 \2', name)
name
# '今天真开心 happy 快乐'

两个表达式是类似地,只不过第一个表达式是在英文和中文字符之间加上空格,第二个表达式是在中文和英文字符之间加上空格。我们来看第一个表达式。第一个()是匹配1个或多个英文,第二个()是匹配1个或多个中文字符,r'\1 \2'是匹配第1个分组和第2个分组,且中间加了空格。

作业2:将格式如"年-月-日"的日期表示法替换成"日/月/年"的方法表示。

答案:

re.sub("(\d{4})-(\d{2})-(\d{2})", r"\2/\3/\1", "2010-12-22")
# 12/22/2010
re.sub("(\d{4})-(\d{2})-(\d{2})", r"\1年\2年\3日", "2010-12-22")
# 2010年12月22日

因为\1,\2不是字符串中的合法转义序列,所以必须指定为原生字符串,在字符串前面加一个"r"。

如果想引用整个表达式匹配的文本,不能使用\0,因为\0开头的转义序列通常表示用八进制形式表示的字符,\0本身表示ASCII字符编码为0的字符。如果一定要引用整个表达式匹配的文本,则可以稍加变通,给整个表达式加上一对括号,之后用\1来引用。

re.sub("((\d{4})-(\d{2})-(\d{2}))", "[\\1]", "2010-12-22")
# [2010-12-22]
re.sub("((\d{4})-(\d{2})-(\d{2}))", r"[\1]", "2010-12-22")
# [2010-12-22]

\num的用法可能产生二义性,例如\10是表示第10个捕获分组还是第1个捕获分组之后跟着一个字符0呢?

在Python中,\10会被解释成第10个捕获分组匹配的文本,下面的程序会报错:

print(re.sub(r"(\d)", r"\10", "123"))

如果希望效果是第1个捕获分组之后跟着一个字符0,那就要写成\g<1>0

re.sub(r"(\d)", r"\g<1>0", "123")
# 102030

(8)re.subn(pattern, repl, string, count=0, flags=0)

行为与 sub()相同,但是返回一个元组 (字符串, 替换次数).

re.subn(r'\sAND\s', ' & ', 'Baked Beans And Spam', flags=re.IGNORECASE)
# ('Baked Beans & Spam', 1)

(9)re.escape(pattern)

转义 pattern 中的特殊字符。

print(re.escape('http://www.python.org'))
# http://www\.python\.org

legal_chars = string.ascii_lowercase + string.digits + "!#$%&'*+-.^_`|~:"
print('[%s]+' % re.escape(legal_chars))
# [abcdefghijklmnopqrstuvwxyz0123456789!\#\$%\&'\*\+\-\.\^_`\|\~:]+

operators = ['+', '-', '*', '/', '**']
print('|'.join(map(re.escape, sorted(operators, reverse=True))))
# /|\-|\+|\*\*|\*

(10)re.purge()

清除正则表达式的缓存。

二、Match对象

匹配对象支持以下方法和属性

(1)Match.expand(template)

对template进行反斜杠转义替换并且返回。转义如同 被转换成合适的字符,数字引用(\1, \2)和命名组合(\g<1>, \g<name>) 替换为相应组合的内容。

m = re.match(r"(\w+) (\w+)", "Isaac Newton, physicist")
m.expand(r"\1\n\2")
# 'Isaac\nNewton'

###(2)Match.group([group1, ...])

m = re.match(r"(\w+) (\w+)", "Isaac Newton, physicist")
m.group(0)
# 'Isaac Newton'
m.group(1)
# 'Isaac'
m.group(2)
# 'Newton'
m.group(1, 2)
# ('Isaac', 'Newton')

另一个例子:

re.search("(\d{4})-(\d{2})-(\d{2})", "2010-12-22").group(1)
# 2010
re.search("(\d{4})-(\d{2})-(\d{2})", "2010-12-22").group(2)
# 12
re.search("(\d{4})-(\d{2})-(\d{2})", "2010-12-22").group(3)
# 22
re.search("(\d{4})-(\d{2})-(\d{2})", "2010-12-22").group(0)
# 2010-12-22
re.search("(\d{4})-(\d{2})-(\d{2})", "2010-12-22").group()
# 2010-12-22

注意,如果被匹配多次,就返回最后一个匹配:

re.search("(\d{4})-(\d{2})-(\d{2})", "2010-12-22").group(1)
# 2010
re.search("(\d){4}-(\d{2})-(\d{2})", "2010-12-22").group(1)
# 0
# 编号为1的分组匹配的文本的值依次是2、0、1、0,最后的结果是0

上面的分组编号是1、2、3等数字编号,当分组多了之后难以记忆,而且很难对应到希望捕获的相应分组上。这时可以用命名分组。

命名分组也就是标识分组为容易记忆和辨别的名字,而不是数字编号。

Python中用(?P<name>regex)来分组。例如:

namedRegex = r"(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})"
result = re.search(namedRegex, "2010-12-22")
print(result.group("year"))  # 2010,等价于result.group(1)
print(result.group("month"))  # 12,等价于result.group(2)
print(result.group("day"))  # 22,等价于result.group(3)

即便使用了命名分组,每个命名分组同时也具有数字编号。

Python中,如果使用了命名分组,在表达式反向引用时,必须使用(?P=name)的记法,而要进行正则表达式替换,则要写作\g<name>

re.search(r"^(?P<char>[a-z])(?P=char)$", "aa") != None  #True
re.sub("(?P<digit>\d)", r"\g<digit>0", "123")  # 102030

###(3)Match._getitem_(g)

等价于m.group(g)

m = re.match(r"(\w+) (\w+)", "Isaac Newton, physicist")
m[0]      
#'Isaac Newton'
m[1]      
#'Isaac'
m[2]       
#'Newton'

###(4)Match.groups(default=None)

返回一个元组,包含所有匹配的子组,在样式中出现的从1到任意多的组合。 default 参数用于不参与匹配的情况,默认为 None。

m = re.match(r"(\d+)\.(\d+)", "24.1632")
m.groups()
# ('24', '1632')

如果我们使点号可选,那么不是所有的组都会有匹配结果。这些组合默认会返回一个 None ,除非指定了 default 参数。

m = re.match(r"(\d+)\.?(\d+)?", "24")
m.groups()
# ('24', None)
m.groups('0')
# ('24', '0')

###(5)Match.groupdict(default=None)

返回一个字典,包含了所有的 命名 子组。key就是组名。 default 参数用于不参与匹配的组合;默认为 None。 例如

m = re.match(r"(?P<first_name>\w+) (?P<last_name>\w+)", "Malcolm Reynolds")
m.groupdict()
# {'first_name': 'Malcolm', 'last_name': 'Reynolds'}

###(6)Match.start(group=0)和Match.end(group=0)

返回 group 匹配到的字串的开始和结束位置。group 默认为0(意思是整个匹配的子串)。如果 group 存在,但未产生匹配,就返回 -1 。

email = "tony@tiremove_thisger.net"
m = re.search("remove_this", email)
email[:m.start()] + email[m.end():]
# 'tony@tiger.net'

###(7)Match.span(group=0)

对于一个匹配 m , 返回一个二元组 (m.start(group), m.end(group)) 。 注意如果 group 没有在这个匹配中,就返回 (-1, -1) 。group 默认为0,就是整个匹配。

email = "tony@tiremove_thisger.net"
m = re.search("remove_this", email)
m.span()
# (7, 18)
email[m.span()[0]:m.span()[1]]
# 'remove_this'

###(8)Match.pos和Match.endpos

pos和endpos的值,会传递给 search() 或 match()的方法一个正则对象。这个是正则引擎开始(对应pos)或停止(对应endpos)在字符串搜索一个匹配的索引位置。

email = "tony@tiremove_thisger.net"
m = re.search("remove_this", email)
m.pos, m.endpos
# (0, 25)

###(9)Match.lastindex

捕获组的最后一个匹配的整数索引值,如果没有匹配产生的话就是 None 。

例如:

result = re.search(r"(a)b", "ab")
result.lastindex
# 1

result = re.search(r"((a)(b))", "ab")
result.lastindex
# 1

result = re.search(r"((ab))", "ab")
result.lastindex
# 1

result = re.search(r"(a)(b)", "ab")
result.lastindex
# 2

###(10)Match.lastgroup

最后一个匹配的命名组名字,如果没有产生匹配的话就是 None 。

namedRegex = r"(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})"
result = re.search(namedRegex, "2010-12-22")
result.lastgroup
# 'day'

###(11)Match.re

返回产生这个实例的正则对象, 这个实例是由 正则对象的 match()或 search()方法产生的。

email = "tony@tiremove_thisger.net"
m = re.search("remove_this", email)
m.re
# re.compile(r'remove_this', re.UNICODE)

###(12)Match.string

传递到match()或search()的字符串。

email = "tony@tiremove_thisger.net"
m = re.search("remove_this", email)
m.string
# "tony@tiremove_thisger.net"

三、flags参数

flags参数是正则表达式使用时的控制标记。控制标记用来改变表达式的行为模式,可以用模式修饰符来指定,也可以用预定义的常量(也就是flags的取值)作为特殊参数传入来指定。

模式修饰符即模式名称对应的单个字符,使用时将其填入特定结构(?modifier)中(modifier为模式修饰符),嵌在正则表达式的开头。

模式修饰符写在最开头表示整个正则表达式都指定此模式,如果出现在中间,则表示此模式从这里开始生效;如果出现在某个括号内,那么它的作用范围只限于括号内部。Python的情况不同,不管出现在哪个位置,都对整个正则表达式生效。

flags参数的可取值及其对应的模式修饰符有以下几种:

1.re.A或re.ASCII: 对应模式修饰符a。让 \w, \W, \b, \B, \d, \D, \s 和 \S 只匹配ASCII,而不是Unicode。Python3以上的版本中,正则表达式默认采用Unicode匹配规则(\w能匹配Unicode中的“单词字符”,包括中文字符,\d也能匹配1、2之类的全角数字字符。),如果希望让\d, \w等字符组简记法恢复到ASCII匹配规则,可以使用此模式。

re.match(r"\w+", "中文字符") != None   # True
re.match(r"\w+", "中文字符", re.A) != None   # False
re.match(r"\w+", "abcd", re.A) != None   # True

2.re.DEBUG: 显示编译时的debug信息。

如果遇到复杂的表达式,或者不确定某个表达式的意义,可以通过它来观察。

re.match(r"ab|cd", "ab", re.DEBUG)

# 会输出下列信息
BRANCH
  LITERAL 97
  LITERAL 98
OR
  LITERAL 99
  LITERAL 100
<_sre.SRE_Match object; span=(0, 2), match='ab'>

缩进表示了表达式各结构的层级关系,而字符本身则显示为其码值的十进制表示(比如字符a的码值是十进制的97)。

3.re.I或re.IGNORECASE: 对应模式修饰符i。忽略正则表达式的大小写,使得正则表达式如[A‐Z]能够匹配小写字符。Unicode匹配(比如 Ü 匹配 ü)同样有用,除非设置了re.ASCII标记来禁用非ASCII匹配。

# 大写字母不能匹配小写字母
re.match(r"[A-Z]", "a") != None   # False
# 忽略大小写之后可以匹配
re.match(r"[A-Z]", "a", re.I) != None   # True

4.re.L或re.LOCALE: 对应模式修饰符 L 。由当前语言区域决定 \w, \W, \b, \B 和大小写敏感匹配。这个标记只能对byte样式有效。这个标记不推荐使用,因为语言区域机制很不可靠,它一次只能处理一个"习惯",而且只对8位字节有效。Unicode匹配在Python 3 里默认启用,并可以处理不同语言。

5.re.M或re.MULTILINE: 对应模式修饰符m。多行匹配,影响^和$。这种模式下正则表达式中的^操作符能够将给定字符串的每行当作匹配开始。默认情况下^是匹配整个字符串的开始。

一个多行模式的例子,这里是匹配每一行以数字开头的内容。

multilineString = "1 line\nNot digit\n2 line"
lineBeginWithDigitRegex = r"(?m)^\d.*"
for line in re.findall(lineBeginWithDigitRegex, multilineString):
    print(line)
# 1 line
# 2 line

等价于

multilineString = "1 line\nNot digit\n2 line"
lineBeginWithDigitRegex = r"^\d.*"
for line in re.findall(lineBeginWithDigitRegex, multilineString, re.M):
    print(line)
# 1 line
# 2 line

如果不使用多行模式的话,只能匹配到1 line即第一行的内容。

6.re.S或re.DOTALL: 对应模式修饰符 s 。使得正则表达式中的.操作符能够匹配所有字符,注意.默认匹配除换行外的所有字符。这也称为单行模式。单行模式下所有文本似乎只在一行里,换行符变成了普通字符,因此点号可以匹配。

7.re.U或re.UNICODE:对应模式修饰符 u 。此模式下,\w, \d, \s等字符组简记法的匹配规则会发生改变,比如\w能匹配Unicode中的“单词字符”,包括中文字符,\d也能匹配1、2之类的全角数字字符。在Python3中默认字符串已经是Unicode了,所以这个模式是冗余的。

8.re.X或re.VERBOSE: 对应模式修饰符 x 。这个标记允许你编写更具可读性更友好的正则表达式。通过分段和添加注释。空白符号会被忽略,除非在一个字符集合当中或者由反斜杠转义,或者在 *?, (?: or (?P<…> 分组之内。当一个行内有 # 不在字符集和转义序列,那么它之后的所有字符都是注释。

意思就是下面两个正则表达式等价地匹配一个十进制数字:

a = re.compile(r"""\d +  # the integral part
                   \.    # the decimal point
                   \d *  # some fractional digits""", re.X)
b = re.compile(r"\d+\.\d*")

如果记不住这么多取值也没关系,只需要知道常用的几个就可以了,即不区分大小写模式re.I、单行模式re.S、多行模式re.M、注释模式re.X。

如果需要同时使用多种模式,只要将模式修饰符排列起来就可以了。比如(?mx)表示同时使用多行模式和注释模式。或者将预定义常量用|组合起来,比如re.M|re.X。

四、re.compile函数

compile函数将正则表达式编译成一个正则表达式对象,可以用于匹配。

函数语法:re.compile(pattern, flags=0)

pattern是正则表达式,flags的含义和re.search中的一样。

prog = re.compile(pattern)
result = prog.match(string)

等价于

result = re.match(pattern, string)

如果正则表达式需要多次使用的话,用re.compile()保存正则表达式对象更加高效。

编译后的正则表达式对象支持以下方法和属性:

(1) Pattern.search(string, pos=0, endpos=len(string))

作用和re.search()类似。参数pos给出了字符串中开始搜索的位置索引,参数endpos限定了字符串搜索的结束。即只有从pos到endpos-1的字符会被匹配。如果endpos小于pos,就不会有匹配产生。

pattern = re.compile("d")
pattern.search("dog")  # 匹配,"d"出现在"dog"的第0个位置
# 输出:<re.Match object; span=(0, 1), match='d'>
pattern.search("dog", 1)  # 不匹配,"d"没有出现在字符串"og"中

(2)Pattern.match(string, pos=0, endpos=len(string))

作用和re.match()类似。参数含义和Pattern.search()含义相同。

pattern = re.compile("o")
pattern.match("dog")   #不匹配,因为"o"不是"dog"的起始位置
pattern.match("dog", 1)  # 匹配
# 输出:<re.Match object; span=(1, 2), match='o'>

(3)Pattern.fullmatch(string, pos=0, endpos=len(string))

作用和re.fullmatch()类似。参数含义和Pattern.search()含义相同。

pattern = re.compile("o[gh]")
pattern.fullmatch("dog")  # 整个字符串与正则表达式不匹配
pattern.fullmatch("ogre")  # 整个字符串与正则表达式不匹配
pattern.fullmatch("doggie", 1, 3) # "og"和正则表达式匹配
# 输出:<re.Match object; span=(1, 3), match='og'>

下面的几个函数都和对应的re函数类似,不再赘述。

(4)Pattern.split(string, maxsplit=0)

(5)Pattern.findall(string, pos=0, endpos=len(string))

(6)Pattern.finditer(string, pos=0, endpos=len(string))

(7)Pattern.sub(repl, string, count=0)

(8)Pattern.subn(repl, string, count=0)

(9)Pattern.flags

正则匹配标记,这是可以传递给compile()的参数。

(10)Pattern.groups

捕获到的模式串中组的数量

(11)Pattern.groupindex

映射由 (?P<id>) 定义的命名符号组合和数字组合的字典。如果没有符号组,那字典就是空的。

(12)Pattern.pattern

编译对象的原始样式字符串。

五、其它

条件匹配

Python的正则表达式支持条件匹配。语法是(?(id/name)yes-pattern|no-pattern)。其中id/name是对应捕获分组的名称或者编号,如果该捕获分组成功匹配文本,则后续匹配交由yes-pattern来完成,否则交由no-pattern来完成。no-pattern可以省略。

假设我们需要验证价格:如果前面没有美元符号$,则价格只能包含整数部分,否则还应当包含小数点和两位小数。

regex = r"^(\$)?[0-9]+(?(1)\.[0-9]{2}|)$"
re.search(regex, "34") != None   # True
re.search(regex, "12.00") != None   # False
re.search(regex, "$34") != None   # False
re.search(regex, "$12.00") != None   # True

其中(?(1)\.[0-9]{2}|)就是一个条件匹配表达式,1对应的是(\$)捕获到的内容。如果起始是$符号,则后面的价格部分除了整数部分外,还必须包含小数点和2位小数,即\.[0-9]{2};如果起始不是$符号,价格只能包含整数部分,不能有其它的。这里的no-pattern是省略的。

参考资料

https://docs.python.org/zh-cn/3.9/library/re.html

Previous【备用】正则表达式Next词典匹配

Last updated 3 years ago

Was this helpful?

返回一个或者多个匹配的子组。如果只有一个参数,结果就是一个字符串;如果有多个参数,结果就是一个元组;如果没有参数,整个匹配都被返回。如果一个组N 参数值为 0,相应的返回值就是整个匹配字符串;如果它是一个范围 [1..99],结果就是相应的括号组字符串。如果一个组号是负数,或者大于样式中定义的组数,一个 索引错误就 raise。如果一个组包含在样式的一部分,并被匹配多次,就返回最后一个匹配。

IndexError