Python正则表达式教程-常用文本处理技巧
介绍:
正则表达式用于识别模式(pattern)是否存在于给定的字符(字符串)序列中。它们有助于处理文本数据,这通常是涉及文本挖掘的数据科学项目的先决条件。您一定遇到过一些正则表达式的应用程序:它们在服务器端用于在注册过程中验证电子邮件地址或密码的格式,用于解析文本数据文件以查找,替换或删除某些字符串等。
内容:
正则表达式非常强大,在本教程中,您将学习在Python中使用它们。您将涵盖以下主题:
- Python中的正则表达式
- 基本字符:普通字符
- 通配符:特殊字符
- 重复次数
- 使用正则表达式进行分组
- 贪婪vs非贪婪匹配
- re Python库 --- search() 与 match()
Python中的正则表达式
- 导入re模块
在Python中,re模块支持正则表达式。使用以下命令导入此模块:
- Import re
- 基本模式:普通字符
您可以使用普通字符轻松解决Python中的许多基本模式。普通字符是最简单的正则表达式。它们完全匹配,并且在正则表达式语法中没有特殊含义。
示例为" A"," a"," X"," 5"。
普通字符可用于执行简单的完全匹配:
- >>>Import re
- >>>pattern = r"Cookie"
- >>>sequence = "Cookie"
- >>>if re.match(pattern, sequence):
- >>> print("Match!")
- >>>else:
- >>> print("Not a match!")
- Match!
match()如果文本与模式匹配,则该函数返回匹配对象。否则返回None。
不过,现在让我们关注普通字符!您是否注意到r模式的开头Cookie?
这称为原始字符串文字。它更改了字符串文字的解释方式。这样的文字会按其出现时进行存储。
例如,\当前缀为a时只是一个反斜杠,r而不是被解释为转义序列。您将看到带有特殊字符的含义。有时,语法涉及反斜杠转义的字符,并且为了防止将这些字符解释为转义序列,请使用原始r前缀。在本示例中,您实际上并不需要它,但是使用它来保持一致性是一种很好的做法。
- 通配符:特殊字符
特殊字符是与正则表达式不匹配但在正则表达式中使用时实际上具有特殊含义的字符。
最广泛使用的特殊字符是:
- . -匹配除换行符以外的任何单个字符。
- re.search(r'Co.k.e', 'Cookie').group()
- 'Cookie'
该group()函数返回与匹配的字符串re。稍后您将更详细地看到此功能。
- \w - 小写w。匹配任何单个字母,数字或下划线。
- re.search(r'Co\wk\we', 'Cookie').group()
- 'Cookie'
- \W - 大写w。匹配不属于\ w的任何字符(小写w)。
- re.search(r'C\Wke', 'C@ke').group()
- 'C@ke'
- \s - 小写字母s。匹配单个空格字符,例如:空格,换行符,制表符,返回值。
- re.search(r'Eat\scake', 'Eat cake').group()
- 'Eat cake'
- \S - 大写字母s。匹配不属于\ s(小写s)的任何字符。
- re.search(r'Cook\Se', 'Cookie').group()
- 'Cookie'
- \t - 小写字母t。匹配标签。
- re.search(r'Eat\tcake', 'Eat cake').group()
- 'Eat\tcake'
- \n - 小写字母n。匹配换行符。
- \r - 小写字母r。比赛归来。
- \d - 小写字母d。匹配十进制数字0-9。
- re.search(r'c\d\dkie', 'c00kie').group()'c00kie'
- ^-插入符号 在字符串的开头匹配一个模式。
- re.search(r'^Eat', 'Eat cake').group()'Eat'
- $ -匹配字符串末尾的模式。
- re.search(r'cake$', 'Eat cake').group()
- 'cake'
[abc] -匹配a或b或c。
[a-zA-Z0-9]-匹配(a至z)或(A至Z)或(0至9)中的任何字母。可以通过补充集合来匹配不在范围内的字符。如果集合的第一个字符是^,则所有不在集合中的字符都将被匹配。
- re.search(r'Number: [0-6]', 'Number: 5').group()
- 'Number: 5'
- # Matches any character except 5
- re.search(r'Number: [^5]', 'Number: 0').group()
- 'Number: 0'
- \A-大写a。仅在字符串开头匹配。也可以跨多行工作。
- re.search(r'\A[A-E]ookie', 'Cookie').group()
- 'Cookie'
- \b-小写字母b。仅匹配单词的开头或结尾。
- re.search(r'\b[A-E]ookie', 'Cookie').group()
- 'Cookie'
- \-反斜杠。如果反斜杠后面的字符是公认的转义字符,则采用该术语的特殊含义。例如,\n被视为换行符。但是,如果后面的字符\不是可识别的转义字符,则将\象任何其他字符一样对待并通过。
让我们看几个例子:
- # This checks for '\' in the string instead of '\t' due to the '\' used
- re.search(r'Back\\stail', 'Back\stail').group()
- 'Back\\stail'
- # This treats '\s' as an escape character because it lacks '\' at the start of '\s'
- re.search(r'Back\stail', 'Back tail').group()
- 'Back lash'
- 重复次数
如果您要查找序列中的长模式,将变得非常乏味。幸运的是,该re模块使用以下特殊字符处理重复:
- + -检查其左侧的一个或多个字符。
- re.search(r'Co+kie', 'Cooookie').group()
- 'Cooookie'
- * -检查左侧是否有零个或多个字符。
- # Checks for any occurrence of a or o or both in the given sequence
- re.search(r'Ca*o*kie', 'Caokie').group()
- 'Caokie'
- ? -检查其左边是否为零或一个字符。
- # Checks for exactly zero or one occurrence of a or o or both in the given sequence
- re.search(r'Colou?r', 'Color').group()
- 'Color'
但是,如果您要检查序列重复的确切数目怎么办?
例如,检查应用程序中电话号码的有效性。re模块还使用以下正则表达式很好地处理了此问题:
{x} -重复x次。
{x,} -重复至少x次或更多。
{x, y} -重复至少x次,但不超过y次。
- re.search(r'\d{9,10}', '0987654321').group()
- '0987654321'
将+和*资格赛被认为是greedy。
- 使用正则表达式进行分组和分组
假设,当您验证电子邮件地址并想要分别检查用户名和主机时。
这是group正则表达式功能派上用场的时候。它允许您拾取匹配文本的一部分。
由括号()界定的正则表达式模式的部分称为groups。括号不会更改表达式匹配的内容,而是在匹配的序列内形成组。group()在本教程的示例中,您一直都在使用该功能。match.group()像平常一样,没有任何参数的纯文本仍然是整个匹配文本。
- email_address = 'Please contact us at: [email protected]'
- match = re.search(r'([\w\.-]+)@([\w\.-]+)', ____________)
- if _____:
- print(match.group()) # The whole matched text
- print(match.group(1)) # The username (group 1)
- print(match.group(2)) # The host (group 2)
贪婪vs非贪婪匹配
当特殊字符与搜索序列(字符串)尽可能匹配时,则称为"贪婪匹配"。这是正则表达式的正常行为,但有时不希望出现这种行为:
- pattern = "cookie"
- sequence = "Cake and cookie"
- heading = r'<h1>TITLE</h1>'
- re.match(r'<.*>', heading).group()
- '<h1>TITLE</h1>'
该模式<.*>匹配整个字符串,直到第二次出现为止>。
但是,如果只想匹配第一个
标记,则可以使用贪婪的限定符*?,该限定符匹配的文字越少越好。
?在限定符之后添加使其以非贪婪或最小的方式执行匹配;也就是说,将匹配尽可能少的字符。跑步时<.*>,您只会与比赛<h1>。
- heading = r'<h1>TITLE</h1>'
- re.match(r'<.*?>', heading).group()
- '<h1>'
re Python库
Re Python中的库提供了几个函数,使其值得掌握。您已经看过其中的一些,例如re.search(),re.match()。让我们详细检查一些有用的功能:
- search(pattern, string, flags=0)
使用此功能,您可以扫描给定的字符串/序列,以查找正则表达式产生匹配项的第一个位置。如果找到,则返回相应的匹配对象;否则,None如果字符串中没有位置与模式匹配,则返回。请注意,这None与在字符串中的某个点找到零长度匹配不同。
- pattern = "cookie"
- sequence = "Cake and cookie"
- re.search(pattern, sequence).group()
- 'cookie'
- match(pattern, string, flags=0)
如果字符串开头的零个或多个字符与模式匹配,则返回相应的匹配对象。否则None,如果字符串与给定的模式不匹配,则返回。
- pattern = "C"
- sequence1 = "IceCream"
- # No match since "C" is not at the start of "IceCream"
- re.match(pattern, sequence1)
- sequence2 = "Cake"
- re.match(pattern,sequence2).group()
- 'C'
search() 与 match()
该match()函数仅在字符串的开头检查匹配项(默认情况下),而该search()函数在字符串的任何位置检查匹配项。
- findall(pattern, string, flags=0)
查找整个序列中所有可能的匹配项,并将它们作为字符串列表返回。每个返回的字符串代表一个匹配项。
- email_address = "Please contact us at: [email protected], [email protected]"
- #'addresses' is a list that stores all the possible match
- addresses = re.findall(r'[\w\.-]+@[\w\.-]+', email_address)for address in addresses:
- print(address)
- [email protected]
- [email protected]
- sub(pattern, repl, string, count=0, flags=0)
这就是substitute功能。它返回通过用替换替换或替换字符串中最左边的非重叠模式所获得的字符串repl。如果找不到该模式,则该字符串将原样返回。
- email_address = "Please contact us at: [email protected]"
- new_email_address = re.sub(r'([\w\.-]+)@([\w\.-]+)', r'[email protected]', email_address)
- print(new_email_address)
- Please contact us at: [email protected]
- compile(pattern, flags=0)
将正则表达式模式编译为正则表达式对象。当您需要在单个程序中多次使用表达式时,使用该compile()函数保存生成的正则表达式对象以供重用会更有效。这是因为compile()缓存了传递给的最新模式的编译版本以及模块级匹配功能。
- pattern = re.compile(r"cookie")
- sequence = "Cake and cookie"
- pattern.search(sequence).group()
- 'cookie'
- # This is equivalent to:
- re.search(pattern, sequence).group()
- 'cookie'
提示:可以通过指定flags值来修改表达式的行为。您可以flag在本教程中看到的各种功能中添加一个额外的参数。一些使用的标志是:IGNORECASE,DOTALL,MULTILINE,VERBOSE,等。
案例研究:使用正则表达式
通过学习一些示例,您已经了解了正则表达式在Python中的工作方式,是时候动手了!在本案例研究中,您将运用自己的知识。
- import reimport requests
- the_idiot_url = 'https://www.gutenberg.org/files/2638/2638-0.txt'
- def get_book(url):
- # Sends a http request to get the text from project Gutenberg
- raw = requests.get(url).text
- # Discards the metadata from the beginning of the book
- start = re.search(r"\*\*\* START OF THIS PROJECT GUTENBERG EBOOK .*\*\*\*",raw ).end()
- # Discards the metadata from the end of the book
- stop = re.search(r"II", raw).start()
- # Keeps the relevant text
- text = raw[start:stop]
- return text
- def preprocess(sentence):
- return re.sub('[^A-Za-z0-9.]+' , ' ', sentence).lower()
- book = get_book(the_idiot_url)
- processed_book = preprocess(book)
- print(processed_book)
在语料库中找到代词" the"的编号。提示:使用len()功能。
- len(re.findall(r'the', processed_book))
- 302
尝试将语料库中的每个" i"的独立实例转换为" I"。确保不要更改一个单词中出现的" i":
- processed_book = re.sub(r'\si\s', " I ", processed_book)
- print(processed_book)
查找""语料库中有人被引号()的次数。
- len(re.findall(r'\"', book))
- 96
什么是由连接的话'--'在语料库?
- re.findall(r'[a-zA-Z0-9]*--[a-zA-Z0-9]*', book)
- ['ironical--it',
- 'malicious--smile',
- 'fur--or',
- ------------省略
- ]
结束