《从 0 到 1 掌握正则表达式:解析串口数据的万能钥匙》
引语
在物联网开发的世界里,串口数据如同流淌的数字血液,每一行字符都藏着环境监测的秘密。当你面对[321022] T:25 C H:68% L:0%
这样的数据流时,正则表达式就像一把精准的瑞士军刀 —— 它能从混乱的字符中切割出时间戳、温度、湿度等关键信息,让 STM32 传感器的数据乖乖 “对号入座”。
本文将带你拆解正则表达式的核心语法,从\d+
匹配数字到()
捕获组提取数据,再到通过re.match()
从字符串开头精准锁定目标。无论你是想解析气象监测数据,还是开发传感器数据管理系统,掌握这把 “数字手术刀”,就能让每一行串口输出都成为可解读的洞察,让代码在数据洪流中开辟出清晰的航道。
点关注不迷路哟。你的点赞、收藏,一键三连,是我持续更新的动力哟!!!
主页:
一位搞嵌入式的 genius-CSDN博客https://blog.csdn.net/m0_73589512?spm=1000.2115.3001.5343
目录
python自动化采集数据脚本:常用函数解析
1. fetchone(self) 方法解析
功能说明
使用场景
2. execute(self, query, args=None) 方法解析
功能说明
使用场景
3. commit(self) 方法解析
功能说明
使用场景
4. 整体逻辑总结
游标工作流程示例
5. 扩展知识:游标与连接的关系
6. 正则表达式基本语法规则
7. 正常数据正则表达式解析
模式分解说明
匹配示例
8. 错误数据正则表达式解析
模式分解说明
匹配示例
9. 正则表达式核心元字符说明
10. 扩展:正则表达式进阶写法
1. 匹配小数温度(如 25.5°C)
2. 匹配更灵活的空白字符
3. 添加行首尾匹配
11. 正则表达式测试方法
测试步骤
12. 正则表达式最佳实践
13. 函数 match(pattern, string, flags=0) 解析
一、函数功能概述
二、参数详解
三、实现逻辑解析
四、与其他匹配函数的对比
五、flags 参数常用取值
六、Match 对象常用方法和属性
七、使用场景建议
八、注意事项
python自动化采集数据脚本:常用函数解析
1. fetchone(self)
方法解析
def fetchone(self):"""Fetch the next row."""self._check_executed()if self._rows is None or self.rownumber >= len(self._rows):return Noneresult = self._rows[self.rownumber]self.rownumber += 1return result
功能说明
-
获取查询结果的下一行数据:从结果集中按顺序获取一行数据
-
关键逻辑:
-
self._check_executed()
:检查是否已执行查询(防止未查询就获取数据) -
检查结果集是否存在(
self._rows is None
)或是否已取完数据(rownumber >= len(self._rows)
) -
若数据存在,返回当前行(
self._rows[self.rownumber]
)并将行号(rownumber
)加 1
-
-
返回值:
-
成功:返回结果集中的下一行数据(元组或字典)
-
失败:返回
None
(无更多数据或查询未执行)
-
使用场景
-
逐行处理查询结果(如需要控制数据读取节奏时)
-
示例:
cursor.execute("SELECT * FROM users") row = cursor.fetchone() while row:print(row)row = cursor.fetchone()
2. execute(self, query, args=None)
方法解析
def execute(self, query, args=None):"""Execute a query. :param query: Query to execute.:type query: str :param args: Parameters used with query. (optional):type args: tuple, list or dict :return: Number of affected rows.:rtype: int"""while self.nextset():pass query = self.mogrify(query, args) result = self._query(query)self._executed = queryreturn result
功能说明
-
执行 SQL 查询语句:接收 SQL 查询和参数,执行后返回受影响的行数
-
关键逻辑:
-
while self.nextset(): pass
:跳过之前查询的结果集(处理多结果集场景) -
query = self.mogrify(query, args)
:将参数绑定到 SQL 查询中(防 SQL 注入) -
result = self._query(query)
:执行实际的查询操作 -
记录已执行的查询(
self._executed = query
)并返回受影响行数
-
-
参数说明:
-
query
:SQL 查询语句(如SELECT * FROM users WHERE id = %s
) -
args
:查询参数(支持tuple/list
(对应%s
)或dict
(对应%(name)s
))
-
使用场景
-
执行增删改查操作(INSERT/UPDATE/DELETE/SELECT)
-
示例:
# 使用tuple参数 cursor.execute("INSERT INTO users(name, age) VALUES(%s, %s)", ("张三", 25)) # 使用dict参数 cursor.execute("SELECT * FROM users WHERE age > %(min_age)s", {"min_age": 18})
3. commit(self)
方法解析
def commit(self):"""Commit changes to stable storage. See `Connection.commit() <https://www.python.org/dev/peps/pep-0249/#commit>`_in the specification."""self._execute_command(COMMAND.COM_QUERY, "COMMIT")self._read_ok_packet()
功能说明
-
提交事务:将未提交的事务变更持久化到数据库
-
关键逻辑:
-
self._execute_command(COMMAND.COM_QUERY, "COMMIT")
:发送 COMMIT 命令到数据库 -
self._read_ok_packet()
:读取数据库返回的确认包(确保提交成功)
-
-
重要性:
-
若不调用
commit()
,事务中的变更不会保存到数据库 -
通常在执行 INSERT/UPDATE/DELETE 后需要调用
-
使用场景
-
数据库事务管理:
try:cursor.execute("BEGIN") # 开始事务cursor.execute("UPDATE accounts SET balance = balance - 100 WHERE id = 1")cursor.execute("UPDATE accounts SET balance = balance + 100 WHERE id = 2")connection.commit() # 提交事务 except:connection.rollback() # 回滚事务
4. 整体逻辑总结
这三个方法是数据库游标(Cursor)的核心功能,对应 Python 数据库 API 规范(PEP-249)中的标准接口:
-
execute()
:执行 SQL 查询,支持参数化查询 -
fetchone()
:按顺序获取查询结果的下一行 -
commit()
:提交事务,确保数据变更持久化
游标工作流程示例
# 1. 执行查询 cursor.execute("SELECT id, name FROM users WHERE age > 18") # 2. 逐行获取结果 row1 = cursor.fetchone() # 获取第一行 row2 = cursor.fetchone() # 获取第二行 # 3. 提交事务(若有变更) connection.commit()
5. 扩展知识:游标与连接的关系
-
游标(Cursor):
-
用于执行 SQL 语句和遍历结果集的对象
-
每个游标独立维护查询状态(如当前行号)
-
-
连接(Connection):
-
与数据库的物理连接,管理事务状态
-
多个游标可共享同一个连接
-
-
最佳实践:
-
用完游标后及时关闭(
cursor.close()
) -
事务完成后及时提交或回滚
-
避免长时间持有数据库连接
-
6. 正则表达式基本语法规则
正则表达式是一种用于匹配文本模式的工具,由普通字符和特殊字符(元字符)组成。以下是核心规则:
7. 正常数据正则表达式解析
normal_pattern = r'\[(\d+)\]\s+T:(\d+)\s*C\s+H:(\d+)\s*%\s+L:(\d+)\s*%'
模式分解说明
模式部分 | 解释 |
---|---|
r'\[' | 匹配左方括号[ (r 表示原始字符串,避免\ 转义问题) | | (\d+) | 捕获组1:匹配1个或多个数字(时间戳) | | \] | 匹配右方括号] |
\s+ | 匹配 1 个或多个空白字符(空格、制表符等) |
T: | 匹配文本T: |
(\d+) | 捕获组 2:匹配温度值(整数) |
\s* | 匹配 0 个或多个空白字符 |
C | 匹配温度单位C |
\s+ | 匹配 1 个或多个空白字符 |
H: | 匹配文本H: |
(\d+) | 捕获组 3:匹配湿度值(整数) |
\s*% | 匹配湿度单位% (允许前后有空白) |
\s+ | 匹配 1 个或多个空白字符 |
L: | 匹配文本L: |
(\d+) | 捕获组 4:匹配光照值(整数) |
\s*% | 匹配光照单位% (允许前后有空白) |
匹配示例
-
输入:
[321022] T:25 C H:68% L:0%
-
匹配结果:
-
捕获组 1:
321022
(时间戳) -
捕获组 2:
25
(温度) -
捕获组 3:
68
(湿度) -
捕获组 4:
0
(光照)
-
8. 错误数据正则表达式解析
error_pattern = r'\[(\d+)\]\s+DHT11\s+Error!\s+L:(\d+)\s*%'
模式分解说明
模式部分 | 解释 |
---|---|
r'\[' | 匹配左方括号[ | | (\d+) | 捕获组1:匹配时间戳 | | \] | 匹配右方括号] |
\s+ | 匹配 1 个或多个空白字符 |
DHT11 | 匹配文本DHT11 |
\s+ | 匹配 1 个或多个空白字符 |
Error! | 匹配文本Error! |
\s+ | 匹配 1 个或多个空白字符 |
L: | 匹配文本L: |
(\d+) | 捕获组 2:匹配光照值(整数) |
\s*% | 匹配光照单位% (允许前后有空白) |
匹配示例
-
输入:
[405018] DHT11 Error! L:2%
-
匹配结果:
-
捕获组 1:
405018
(时间戳) -
捕获组 2:
2
(光照)
-
9. 正则表达式核心元字符说明
元字符 | 含义 |
---|---|
\ | 转义字符,用于匹配特殊字符(如[ 、] 、\s 等) |
[] | 字符集,匹配方括号内的任意字符(如[0-9] 匹配数字) |
() | 捕获组,用于提取匹配的子字符串(如(\d+) 提取数字) |
\d | 匹配数字(等价于[0-9] ) |
\s | 匹配空白字符(空格、制表符、换行符等) |
+ | 量词:匹配 1 次或多次(如\d+ 匹配至少 1 个数字) |
* | 量词:匹配 0 次或多次(如\s* 匹配 0 个或多个空白) |
\A | 匹配字符串开头 |
\Z | 匹配字符串结尾 |
| | 或操作(如a|b 匹配a 或b ) |
10. 扩展:正则表达式进阶写法
1. 匹配小数温度(如 25.5°C)
normal_pattern = r'\[(\d+)\]\s+T:(\d+\.\d+|\d+)\s*C\s+H:(\d+)\s*%\s+L:(\d+)\s*%'
-
(\d+\.\d+|\d+)
:匹配整数或小数(如25
或25.5
)
2. 匹配更灵活的空白字符
normal_pattern = r'\[(\d+)\](\s+)T:(\d+)\s*C\s*H:(\d+)\s*%\s*L:(\d+)\s*%'
-
(\s+)
:明确匹配时间戳后的空白字符
3. 添加行首尾匹配
normal_pattern = r'^\[(\d+)\]\s+T:(\d+)\s*C\s+H:(\d+)\s*%\s+L:(\d+)\s*%$'
-
^
:匹配行开头 -
$
:匹配行结尾,确保整行完全匹配
11. 正则表达式测试方法
推荐使用在线工具测试正则表达式,例如:
-
Regex101:可视化匹配过程,显示捕获组结果
-
Pythex:专门用于 Python 正则表达式测试
测试步骤
-
输入正则表达式
-
输入测试字符串
-
查看匹配结果和捕获组内容
-
根据结果调整正则表达式
12. 正则表达式最佳实践
-
使用原始字符串:
r'\[(\d+)\]' # 推荐,避免\转义问题 '\[(\d+)\]' # 不推荐,需处理\转义
-
明确匹配范围:
-
尽量使用
^
和$
匹配行首尾,避免部分匹配 -
示例:
^Pattern$
比Pattern
更精确
-
-
分组清晰:
-
按逻辑分组,便于后续提取数据
-
不需要提取的分组使用非捕获组:
(?:pattern)
-
-
逐步构建:
-
先编写简单模式,再逐步添加复杂条件
-
例如:先匹配时间戳
\[\d+\]
,再添加温度部分T:\d+C
-
通过理解这些规则,可以根据实际数据格式灵活调整正则表达式,确保准确匹配和数据提取。如果需要匹配更复杂的格式,可逐步扩展模式并通过测试验证匹配效果。
13. 函数 match(pattern, string, flags=0)
解析
这个函数是 Python 中 re
模块的 match()
函数实现,用于从字符串开头尝试匹配正则表达式模式。以下是对其功能、参数和实现逻辑的详细解析:
一、函数功能概述
def match(pattern, string, flags=0):"""Try to apply the pattern at the start of the string, returninga Match object, or None if no match was found."""return _compile(pattern, flags).match(string)
-
核心功能:从字符串的开头开始尝试匹配正则表达式模式
-
返回值:
-
匹配成功:返回
Match
对象(包含匹配结果和分组信息) -
匹配失败:返回
None
-
-
关键调用:
-
_compile(pattern, flags)
:编译正则表达式模式 -
match(string)
:在字符串上执行匹配操作
-
二、参数详解
参数 | 类型 | 说明 |
---|---|---|
pattern | str | 正则表达式模式字符串(如 r'\d+' 匹配数字) |
string | str | 要匹配的目标字符串(如 "123abc" ) |
flags | int | 匹配标志(可选,默认 0),用于修改匹配行为,例如: |
- re.I :忽略大小写 - re.M :多行匹配 - re.S :点号匹配所有字符 |
三、实现逻辑解析
-
正则表达式编译:
_compile(pattern, flags)
-
将字符串形式的正则表达式
pattern
编译为内部可执行的模式对象 -
编译后可提高匹配效率(避免重复编译相同模式)
-
-
字符串匹配:
.match(string)
-
对
string
执行匹配操作,仅从字符串开头开始匹配 -
若开头不匹配模式,则直接返回
None
,不继续向后匹配
-
-
示例说明:
import re # 匹配成功 result = re.match(r'\d+', '123abc') print(result.group()) # 输出: '123' # 匹配失败(开头不是数字) result = re.match(r'\d+', 'abc123') print(result) # 输出: None
四、与其他匹配函数的对比
函数 | 匹配位置 | 示例(模式\d+ ,字符串'abc123' ) |
---|---|---|
re.match() | 字符串开头 | 匹配失败(返回None ) |
re.search() | 字符串任意位置 | 匹配成功(返回'123' ) |
re.findall() | 查找所有匹配 | 返回['123'] |
五、flags 参数常用取值
re.match(r'abc', 'ABC', re.I).group() # 输出: 'ABC'
-
多行匹配(
re.M
):pattern = r'^Hello' string = """Hello World Hello Python""" # 不使用re.M时仅匹配第一行 re.match(pattern, string).group() # 输出: 'Hello' # 使用re.M时匹配所有行开头 re.match(pattern, string, re.M) # 仍只匹配第一行(match()仅从开头匹配) re.findall(pattern, string, re.M) # 输出: ['Hello', 'Hello']
-
点号匹配所有字符(
re.S
):pattern = r'Hello.*World' string = "Hello\nWorld" re.match(pattern, string).group() # 匹配失败(.不匹配\n) re.match(pattern, string, re.S).group() # 匹配成功(.匹配\n)
六、Match 对象常用方法和属性
方法 / 属性 | 说明 |
---|---|
group(n) | 获取第 n 个捕获组的匹配结果(n=0 为整个匹配结果) |
groups() | 以元组形式返回所有捕获组的结果 |
groupdict() | 以字典形式返回命名捕获组的结果 |
start(n) | 获取第 n 个捕获组的起始位置 |
end(n) | 获取第 n 个捕获组的结束位置 |
span(n) | 获取第 n 个捕获组的起始和结束位置(返回元组(start, end) ) |
七、使用场景建议
-
明确需要从开头匹配时:
-
验证字符串格式(如 IP 地址、邮箱等)
-
示例:验证手机号(开头为 13/14/15/18 等)
def is_valid_phone(phone):return re.match(r'^1[3-9]\d{9}$', phone) is not None
-
-
与其他匹配函数配合使用:
-
先使用
match()
尝试开头匹配,失败后再用search()
全局搜索
def find_pattern(pattern, string):result = re.match(pattern, string)if not result:result = re.search(pattern, string)return result
-
-
结合 flags 参数处理复杂场景:
-
处理包含特殊字符或需要多行匹配的文本
-
八、注意事项
-
仅开头匹配限制:
-
match()
不会搜索字符串中间的匹配项,若需要全局匹配请使用re.search()
-
-
编译后的模式对象:
-
对于频繁使用的正则表达式,建议提前编译以提高效率:
pattern = re.compile(r'\d+') result = pattern.match('123abc')
-
-
转义字符处理:
-
使用原始字符串(
r''
)避免转义问题:
re.match(r'\\d+', '\\d123') # 匹配'\\d' re.match('\\\\d+', '\\d123') # 等价于上面的原始字符串
-
通过理解match()
函数的工作原理和参数用法,可以更精准地控制正则表达式的匹配行为,尤其是在需要从字符串开头进行模式匹配的场景中。