Notice: Function _load_textdomain_just_in_time was called incorrectly. Translation loading for the wp-pagenavi domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early. Translations should be loaded at the init action or later. Please see Debugging in WordPress for more information. (This message was added in version 6.7.0.) in /var/www/blog.zhujinhui.net/wp-includes/functions.php on line 6114

Notice: 函数 _load_textdomain_just_in_time 的调用方法不正确twentyseventeen 域的翻译加载触发过早。这通常表示插件或主题中的某些代码运行过早。翻译应在 init 操作或之后加载。 请查阅调试 WordPress来获取更多信息。 (这个消息是在 6.7.0 版本添加的。) in /var/www/blog.zhujinhui.net/wp-includes/functions.php on line 6114
正则表达式 – 煅魂-JeffreyChu的修炼屋

一文搞定python正则表达式

概念&作用

正则表达式是一种用来描述文本模式的工具,它可以帮助你在字符串中查找匹配替换符合某种模式的文本。通过使用正则表达式,你可以定义一些规则,然后在文本中查找符合这些规则的内容。正则表达式可以用于各种编程语言和文本处理工具中,例如Python、JavaScript、Perl等。

python中的正则表达式

在python中,内置的 re 模块提供了对正则表达式的支持,这使得在 Python 中处理文本数据变得非常方便和高效。正则表达式在 Python 中非常有用,主要是因为re模块具有强大的模式匹配功能、文本处理的灵活性、替换和修改文本的能力以及Python 的易用性和广泛应用。

基础构成

字符

正则表达式中的字符可以是字母、数字或符号,它们代表自身字符。例如,a 匹配字符 “a”。

元字符

元字符是具有特殊含义的字符,它们不仅仅代表自身字符。一些常见的元字符包括

元字符作用含义
.匹配除换行符以外的任意字符。
^匹配字符串的开头。
$匹配字符串的结尾。
\d匹配任意一个数字字符,相当于 [0-9]
\D匹配任意一个非数字字符,相当于 [^0-9]
\w匹配任意一个字母、数字或下划线字符,相当于 [a-zA-Z0-9_]
\W匹配任意一个非字母、数字或下划线字符,相当于 [^a-zA-Z0-9_]
\s匹配任意一个空白字符,包括空格、制表符、换行符等
\S匹配任意一个非空白字符
\b匹配单词边界,即字与空格之间的位置
\B匹配非单词边界
*匹配前一个字符的零个或多个。
+匹配前一个字符的一个或多个。
?匹配前一个字符的零个或一个。
[]匹配方括号内的任意一个字符。例如,[aeiou]匹配任意一个元音字母。
|匹配两个或多个模式之一。
()用于创建捕获组,可以对匹配的内容进行分组。
量词

量词用于指定匹配字符重复出现的次数,常见的量词包括:

量词作用含义
{m}精确匹配前一个字符出现 m 次
{m,n}匹配前一个字符出现至少 m 次,最多 n 次
{m,}匹配前一个字符出现至少 m 次
*匹配前一个字符的零个或多个
+匹配前一个字符的一个或多个
?匹配前一个字符的零个或一个
原始字符串

在Python中,r字符串是一种特殊的字符串表示形式,被称为原始字符串(raw string)。在原始字符串中,反斜杠 \ 不会被解释为转义字符,而是作为普通字符对待。这意味着在原始字符串中,反斜杠后面的字符会保持原样,不会被转义。

例如,在普通字符串中,要表示一个Windows文件路径,你需要使用双反斜杠来转义,如下所示:

path = "C:\\Users\\username\\Documents\\file.txt"

而在原始字符串中,你可以直接写成:

path = r"C:\Users\username\Documents\file.txt"

这使得处理一些特殊字符串,如正则表达式模式或文件路径,更加方便,因为你无需担心转义字符带来的影响。

re模块

Python 的正则表达式模块 re 提供了一系列功能,让你可以在字符串中进行模式匹配、查找和替换等操作。你提到的 re.match()re.search()re.findall()re.sub()re.compile() 是其中常用的几个函数。

re.match

re.match(pattern, string, flags=0)尝试从字符串的开头匹配一个模式。如果字符串开头匹配成功,则返回一个匹配对象;否则返回 None。这意味着它只匹配字符串的开头位置。

import re

pattern = r'hello'
string = 'hello world'
match_obj = re.match(pattern, string)
if match_obj:
    print("Match found:", match_obj.group())
else:
    print("No match found")

# Match found: hello
re.search

re.search(pattern, string, flags=0)re.match(pattern, string, flags=0)类似,但是它在整个字符串中搜索匹配项,返回第一个匹配到的对象。这意味着它可以匹配字符串的任意位置。

import re

pattern = r'world'
string = 'hello world'
search_obj = re.search(pattern, string)
if search_obj:
    print("Match found:", search_obj.group())
else:
    print("No match found")

# Match found: world
re.findall

re.findall(pattern, string, flags=0)在字符串中找到所有匹配项,并以列表的形式返回。它不同于 re.match()re.search(),它不返回匹配对象,而是直接返回匹配的字符串列表。

import re

pattern = r'lo'
string = 'hello world'
matches = re.findall(pattern, string)
print("Matches found:", matches)

# Matches found: ['lo']
re.sub

re.sub(pattern, repl, string, count=0, flags=0)用来在字符串中查找匹配项,并替换为指定的字符串。它返回替换后的新字符串。

import re

pattern = r'world'
replacement = 'universe'
string = 'hello world'
new_string = re.sub(pattern, replacement, string)
print("New string:", new_string)

# New string: hello universe
re.compile

re.compile(pattern, flags=0)是Python 中用于预编译正则表达式模式的函数。这个函数接受一个正则表达式作为参数,并返回一个正则表达式对象,这个对象可以被用来执行匹配操作。这个函数诸多优点:

  • 提高效率: 编译后的正则表达式对象可以在多次使用时提高匹配效率。因为编译后的对象已经将正则表达式模式编译为内部数据结构,避免了每次匹配都要重新解析模式的开销。
  • 可重用性: 编译后的正则表达式对象可以在多个地方使用,而不需要每次都重新编译正则表达式模式,提高了代码的可重用性。
  • 简化代码: 将常用的正则表达式模式预先编译,可以简化代码,使代码更加清晰易懂。
import re

# 编译正则表达式模式
pattern = re.compile(r'\d{3}-\d{3}-\d{4}')

# 使用编译后的对象进行匹配操作
result = pattern.search("John's phone number is 123-456-7890.")
if result:
   print("Phone number found:", result.group())
else:
   print("Phone number not found.")

# Phone number found: 123-456-7890
flag的可选值
  • re.IGNORECASEre.I: 忽略大小写匹配。
  • re.MULTILINEre.M: 多行匹配,使 ^$ 匹配字符串的每行的开头和结尾,而不是整个字符串的开头和结尾。
  • re.DOTALLre.S: 让 . 匹配任何字符,包括换行符。
  • re.UNICODEre.U: 使 \w, \W, \b, \B, \d, \D, \s, \SUnicode 字符集合匹配。
  • re.ASCII: 使 \w, \W, \b, \B, \d, \D, \s, \SASCII 字符集合匹配。
  • re.VERBOSEre.X: 忽略空白和注释,使得更易读的正则表达式能够被编写。

正/反向前瞻

正向前瞻(Positive Lookahead):正向前瞻用 (?=…) 表示,它指定了一个条件,在匹配位置的右侧必须满足这个条件才能匹配成功。但匹配的位置本身不会被包含在匹配结果中。

反向前瞻(Negative Lookahead):反向前瞻用 (?!…) 表示,它指定了一个条件,在匹配位置的右侧必须不满足这个条件才能匹配成功。同样,匹配的位置本身不会被包含在匹配结果中。

接下来演示一下,假设我们要匹配一个字符串中的所有数字,但是要排除包含小数点的数字。我们可以使用正向前瞻来实现这个匹配:

import re

# 匹配所有不包含小数点的数字
pattern = r'\d+(?!\.)'
text = "123 456 7.89 10"

matches = re.findall(pattern, text)
print(matches)

# ['123', '456', '10']

在这个示例中,r'\d+(?!\.)' 匹配的是一串数字 \d+,但是它的右侧不能跟着一个小数点 (?!\.),这样就排除了包含小数点的数字。

反向前瞻也可以用来排除某些特定情况的匹配。例如,假设我们要匹配所有不是以字母 “a” 开头的单词:

import re

# 匹配所有不以字母 "a" 开头的单词
pattern = r'\b(?!a)\w+\b'
text = "apple banana orange"

matches = re.findall(pattern, text)
print(matches)  
# ['banana', 'orange']

在这个示例中,r'\b(?!a)\w+\b' 匹配的是一个单词,但是它的左侧不能以字母 “a” 开头 (?!a),这样就排除了以 “a” 开头的单词 “apple”。

捕获组和非捕获组的概念

在正则表达式中,捕获组和非捕获组是用来对匹配的文本进行分组和提取的工具, 比如Django/Flask等框架的url路由匹配就是用了这个。 捕获组:捕获组用括号 ( ) 表示,它可以将匹配的文本分组并保存到一个单独的组中,以便后续引用或提取。捕获组可以在整个正则表达式中通过反向引用(backreference)或在匹配结果中进行访问。

非捕获组:非捕获组也用括号 ( ) 表示,但是在左括号后紧跟着一个问号和冒号 (?: ),它用于对文本进行分组,但不会在匹配结果中保存分组的内容,也不会创建一个新的捕获组。非捕获组通常用于提高正则表达式的效率,因为它不会占用额外的内存来存储匹配结果。

接下来演示一下, 假设我们有一个包含邮箱地址的字符串,我们想从中提取用户名和域名部分。我们可以使用捕获组来实现:

import re

# 匹配邮箱地址的正则表达式
pattern = r'(\w+)@(\w+\.\w+)'

text = "jeff@xmishu.com, alice@baidu.com"

# 使用捕获组提取用户名和域名
matches = re.findall(pattern, text)
for match in matches:
    username, domain = match
    print("Username:", username)
    print("Domain:", domain)

在这个示例中,(\w+)(\w+\.\w+) 分别是两个捕获组,用来提取用户名和域名。re.findall() 函数会返回一个列表,其中每个元素是一个包含用户名和域名的元组。通过遍历这个列表,我们可以轻松地获取用户名和域名部分。

实际应用

正则表达式在python应用中非常广泛,它能辅助我们高效地处理很多问题

  • 数据提取(网页数据采集等)
  • 文本处理(数据清洗、格式化入库等)
  • web表单中用户输入内容验证(邮箱密码格式验证等)。

注意事项

  • 预编译正则表达式:如果你要在多个地方使用相同的正则表达式,可以使用re.compile()预先编译它,以提高匹配效率,生产环境中很有用。
  • 选择最适合的函数:Python的re模块提供了多个函数用于正则表达式操作,如re.match()re.search()re.findall()等。根据需求选择最适合的函数,以避免不必要的性能开销。
  • 使用非贪婪匹配:在量词后面加上?可以将匹配模式变为非贪婪模式,尽可能少地匹配字符。例如,*?+???
  • **避免过度使用 .**:.可以匹配任意一个字符,但在某些情况下可能会导致性能下降。如果可能,尽量使用更具体的字符集或模式来限制匹配范围。
  • 使用原始字符串:在编写正则表达式时,最好使用原始字符串(以r开头),以避免不必要的转义,提高代码可读性。
  • 使用字符类:字符类(如[0-9][a-zA-Z])比单个字符更有效率,因为它们允许正则引擎更快地确定是否匹配。