最近项目遇到了一个很奇怪的问题,在读取串口数据时,有些数据可以正确转换,有些数据转换出来为空,对比这些数据,从字面上看不出有有什么区别。
然而,在使用 C++ 进行串口通信或其他低层数据处理时,由于数据中可能包含不可见的控制字符(例如 NULL 字符 \0
和其他 ASCII 范围的控制字符),在将这些数据转换为字符串进行显示或存储时,可能会遇到显示异常或乱码的问题。因此,需要清理这些控制字符。
本文将详细讨论如何处理 QByteArray
中的控制字符,包括不同的替换和移除方法,并给出具体代码示例。
1. QByteArray
和控制字符问题
QByteArray
是 Qt 库中用于存储字节数据的容器类。它通常用于处理从串口、文件或网络接收到的原始字节流数据。然而,这些数据流中可能会包含控制字符(ASCII 范围 \x00
到 \x1F
),这些字符在字符串显示中是不可见的,甚至可能导致程序错误或数据显示异常。
控制字符的来源
- 串口通信:从设备读取的数据可能包含无效或不可见的字符。
- 文件读取:某些文件在保存时包含特殊的控制字符。
- 网络数据:接收的数据包中可能包含协议头部的控制字符。
这些控制字符需要在进一步处理前清除,否则可能会引起显示或逻辑错误。
2. 使用 QByteArray::replace()
移除字符
QByteArray
提供了简单的 replace()
方法,可以用来替换字符或字节片段。例如,替换 NULL 字符可以这样操作:
recebuffer.replace('\0', ''); // 替换 NULL 字符为一个空字符
局限性:replace()
函数不能直接处理复杂的模式匹配或正则表达式替换。因此,当你需要替换一系列控制字符(例如所有 ASCII 范围的控制字符)时,replace()
的功能显得非常有限。
3. 使用正则表达式处理控制字符
为了灵活移除一系列的控制字符,可以借助 Qt 中的 QRegularExpression
。但是,由于 QByteArray
不能直接与 QRegularExpression
协同工作,我们需要将 QByteArray
转换为 QString
进行处理。下面是完整的代码示例:
#include <QByteArray>
#include <QString>
#include <QRegularExpression>
#include <QDebug>
int main() {
// 假设 recebuffer 是从串口读取的数据
QByteArray recebuffer = QByteArray::fromHex("48656C6C6F2C20576F726C6421000A0D"); // 包含 NULL 字符和控制字符
// 将 QByteArray 转换为 QString
QString tempStr = QString::fromUtf8(recebuffer);
// 使用 QRegularExpression 移除控制字符(\x00 - \x1F)
tempStr.replace(QRegularExpression("[\\x00-\\x1F]"), "");
// 将 QString 转换回 QByteArray
recebuffer = tempStr.toUtf8();
// 输出结果
qDebug() << "Cleaned QByteArray:" << recebuffer;
return 0;
}
代码解释
- 转换为
QString
:QString::fromUtf8(recebuffer)
将QByteArray
转换为QString
,这使得正则表达式替换变得可行。 - 正则表达式替换:
QRegularExpression("[\\x00-\\x1F]")
匹配所有控制字符,replace()
将其移除。 - 转换回
QByteArray
:tempStr.toUtf8()
将处理后的字符串转换回字节数组,方便继续使用。
这种方法非常灵活,可以处理各种控制字符,是从数据清理到数据显示的推荐方式。