Company : ****** Operator : ****** Time/Date : 13:41:21 June 12, 2025 Sample ID : ****** Measure Program : MTF vs. Field vs. Focus Temperature : 20°C Measured with : TRIOPTICS - MT= F-LAB - Vers. 5.16.1 Instrument S/N : 09-113-0519 Comments : SN215U0540 split('\n')会将这个字符串中间的空格也分割了,我只想再每一行的结尾分割,要用QT+C++实现
时间: 2025-07-02 22:35:36 浏览: 4
<think>我们注意到原始字符串中每一行以换行符结束,但有些行在键和冒号之间可能有多个空格,而且值部分可能包含换行(如"Measuredwith"的值被分成了两行)。因此,我们需要一个更健壮的方法来解析。问题分析:1.原始字符串中,键和冒号之间可能有多个空格,但键是固定的一些词(如"Company", "Operator"等)。2.值部分可能包含换行符(如例子中的"Measuredwith"的值有两行),导致按换行符分割后,有些行可能不包含冒号(如第二行"F-LAB- Vers.5.16.1")。3.我们想要将每一对键值正确提取出来。解决方案:我们可以按以下步骤处理:
a)首先,将整个字符串按换行符分割成行。b)然后,遍历每一行,尝试匹配以已知键开头的行(因为我们知道所有可能的键)。c)如果当前行包含一个键(即包含一个冒号,且冒号前面的部分匹配某个键),那么我们就提取该键和该行冒号后的部分作为值。d)如果当前行不包含键(即没有冒号或者冒号前的内容不是已知键),那么它可能是上一行值的延续,将其追加到上一个键的值中。但是,我们可能不知道所有键?从示例中我们可以看出键是固定的,但为了通用性,我们可以这样:定义已知键的列表,然后按行处理。如果一行中包含某个键(即该行以某个键开头,后面跟着冒号),那么我们就认为这是一个新键值对的开始。另一种思路:我们注意到键的后面都有冒号,并且键是左对齐的(即冒号在同一列)。但观察示例,冒号的位置并不固定(因为键的长度不同)。因此,我们采用以下方法:1.遍历每一行,查找第一个冒号的位置。如果找到,则将该行冒号前面的部分作为键(去除前后空格),冒号后面的部分作为值(去除前后空格)。2.但是,如果一行中没有冒号,那么我们就认为这一行是上一行值的延续,将其追加到上一个键的值中(并在前面加一个空格或者换行符,根据需求)。因此,我们修改代码:步骤:-初始化一个空的QMap来存储键值对。-初始化一个变量来保存当前的键(用于多行值的情况)。-按行遍历:a.如果当前行包含冒号(并且我们假设第一个冒号是键值分隔符):-提取键(从行开始到冒号,并去除空格)-提取值(从冒号后到行尾,去除空格)-将当前键设置为这个键,并将这个键值对存入map(如果这个键之前已经出现,那么我们可以覆盖或者报错?根据需求)b.如果当前行不包含冒号:-如果当前键不为空(即之前已经有一个键),那么将这一行追加到该键的值中(可以加一个空格或换行符,根据原始格式需求)-否则,忽略这一行(或者视为错误?)但是,注意示例中有一行是:"F-LAB- Vers.5.16.1",它是"Measuredwith"的值的一部分。所以我们需要将它追加到"Measured with"的值中。示例字符串:
"Measuredwith: TRIOPTICS- MT=\nF-LAB- Vers.5.16.1"注意:在"Measuredwith"那一行,值部分已经有一个换行,所以被分割成两行。第一行是"Measured with:TRIOPTICS -MT=",第二行是"F-LAB- Vers.5.16.1"。因此,我们按上述逻辑处理。代码实现:注意:我们使用一个变量currentKey来记录当前正在处理的键,当遇到新键时,currentKey更新,当遇到没有冒号的行时,我们将其追加到currentKey对应的值中。但是,我们还要注意:第一行肯定是有冒号的,所以currentKey初始为第一个键。另外,追加时,我们使用换行符还是空格?原始数据中,值部分包含换行,所以我们应该保留换行符。因此,在追加时,我们可以在上一行的值后面加上换行符,再加上这一行的内容(或者不加换行符,直接拼接?因为原始字符串中已经换行了,但我们在分割时去掉了换行符,所以需要补上)。但是,原始字符串在分割时,每一行末尾的换行符被去掉了,所以我们在追加时应该加上换行符,或者按照原始格式,我们也可以不加换行符而用空格代替?这取决于需求。观察原始数据,在"Measured with"的值中,第一行末尾有一个等号,第二行开头是"F-LAB",所以它们应该是连在一起的。但是,原始数据中的换行符可能是为了格式,实际意义可能是空格?或者没有空格?从内容看,应该是连在一起形成"TRIOPTICS- MT=F-LAB- Vers.5.16.1",但这样显然不对。实际上,等号后面换行,可能是数据录入时的换行,我们可能需要保留换行,或者用一个空格代替。这里,我们假设值中的换行应该被保留(即用换行符连接)。因此,我们在追加时,在上一行值后面加上换行符,然后加上这一行的内容。但是,如果希望保留原始格式,那么我们就应该用换行符连接。因为原始字符串中就是换行的。然而,在分割字符串时,我们使用split('\n'),这样每一行末尾的换行符被去掉了。所以当我们重新连接时,需要加上换行符。但是,也可以这样:在分割时保留空行?我们使用的是`Qt::SkipEmptyParts`,但换行符还是被去掉了。所以我们需要在解析时重新加上换行。不过,我们也可以选择在分割时不使用`split`的简化版本,而是用`QString::split`并保留空字符串?但这样不会保留换行符。因此,我们决定:在解析过程中,对于连续的行,我们使用换行符连接。代码:我们使用一个循环,逐行处理,并维护当前键和当前值(在遇到新键时,将上一个键值对保存,然后开始新的键值对;对于没有冒号的行,追加到当前键的值中)。注意:在循环结束后,最后一个键值对需要保存。步骤:-初始化一个QMap(或QHash)来存储结果。-初始化一个QString变量currentKey,初始为空。-初始化一个QString变量currentValue,初始为空。-将整个字符串按行分割(使用split('\n',Qt::SkipEmptyParts)得到行列表)。-遍历每一行:QString line= lines[i];intcolonIndex= line.indexOf(':');if(colonIndex !=-1) {//如果当前已经有currentKey(即之前有一个键值对正在构建),那么先保存它if(!currentKey.isEmpty()) {//保存currentKey和currentValue到mapresultMap[currentKey]= currentValue;//重置currentValuecurrentValue.clear();}//提取新的键和值currentKey =line.left(colonIndex).trimmed();currentValue= line.mid(colonIndex+1).trimmed();}else {//没有冒号,那么如果currentKey不为空,则追加这一行到currentValueif (!currentKey.isEmpty()){//用换行符连接,因为原始数据中就是换行currentValue+= "\n"+ line.trimmed();}//否则,忽略这一行(或视为错误,但这里不处理)}-循环结束后,保存最后一个键值对(如果currentKey不为空)但是,这样会丢失最后一个键值对,所以循环后需要保存。但是,注意:如果第一行就有冒号,那么第一个键值对会在遇到第二个键值对时保存。所以最后一个键值对需要在循环后保存。修改:在循环结束后,检查currentKey是否为空,如果不为空,则保存。但是,这样处理,如果一行中同时有多个冒号,我们只认第一个冒号(如时间行),所以没问题。我们尝试用这个逻辑处理示例中的"Measured with":-遇到"Measured with:TRIOPTICS -MT=",则currentKey变为"Measured with",currentValue变为"TRIOPTICS -MT="。-下一行是"F-LAB -Vers.5.16.1",没有冒号,所以追加:currentValue= "TRIOPTICS- MT=\nF-LAB -Vers.5.16.1"-然后遇到下一行有冒号(如"Instrument S/N"),这时就会保存"Measuredwith"的键值对,并重置currentKey为"Instrument S/N",currentValue为"09-113-0519"。代码实现:注意:在追加时,我们使用`currentValue +="\n" +line.trimmed();`,这样保留了换行。但如果我们不需要换行,可以用空格,这里根据需求。但是,原始数据中换行可能是为了对齐,实际值中可能不需要换行?这取决于数据的用途。如果希望保留原始格式,就保留换行;如果希望值是一个长字符串,那么用换行连接也可以。下面给出完整代码:注意:我们使用QMap,因为键的顺序可能不重要,但QMap会按键排序。如果希望保持原始顺序,可以使用QList<QPair<QString, QString>>或者QVector来存储键值对。这里,我们使用QMap,因为后续可能通过键来访问值。代码:
```cpp#include <QCoreApplication>#include <QString>
#include<QStringList>
#include<QMap>#include <QDebug>
intmain(intargc,char *argv[]){QCoreApplication a(argc, argv);QString data="Company: ******\n""Operator: ******\n""Time/Date:13:41:21June12,2025\n""SampleID: ******\n""Measure Program:MTFvs.Field vs. Focus\n""Temperature:20°C\n""Measured with:TRIOPTICS -MT=\n"//注意这里有一个换行"F-LAB- Vers.5.16.1\n"//这一行没有冒号,是上一行的延续"InstrumentS/N:09-113-0519\n""Comments:SN215U0540";QStringList lines= data.split('\n',Qt::SkipEmptyParts);QMap<QString, QString> resultMap;QStringcurrentKey;QString currentValue;for(inti =0;i <lines.size(); ++i){QString line= lines[i];intcolonIndex= line.indexOf(':');if(colonIndex !=-1) {//如果遇到新的键,先保存之前的键值对(如果有)if(!currentKey.isEmpty()) {resultMap[currentKey]= currentValue;currentValue.clear(); //重置当前值}//提取新键currentKey =line.left(colonIndex).trimmed();//提取新值(从冒号后到行尾)currentValue= line.mid(colonIndex +1).trimmed();}else {//当前行没有冒号,且当前键不为空(即我们在处理一个多行值)if(!currentKey.isEmpty()) {//追加这一行到当前值,我们使用换行符连接currentValue +="\n" +line.trimmed();}//否则,忽略该行(比如在第一个键之前出现无冒号行,这种情况在示例中不会出现)}}//循环结束后,保存最后一个键值对if(!currentKey.isEmpty()) {resultMap[currentKey]= currentValue;}//输出结果qDebug()<< "ParsedKey-Value Pairs:";for (auto it= resultMap.constBegin();it !=resultMap.constEnd(); ++it){qDebug() <<it.key() <<" =>" <<it.value();}return a.exec();}
```###代码解释:1.**分割字符串**:使用`split('\n',Qt::SkipEmptyParts)`将原始字符串分割成行列表,跳过空行。
2. **逐行解析**:-查找每行的第一个冒号位置-如果找到冒号,则:-保存上一个键值对(如果有)-设置当前键(冒号前部分,去除空格)-设置当前值(冒号后部分,去除空格)-如果未找到冒号:-若当前键不为空(表示正在处理一个多行值),则将该行内容追加到当前值(用换行符连接)3.**保存最后键值对**:循环结束后,若当前键非空,则保存最后一对键值4. **输出结果**:使用`qDebug()`打印解析后的键值对###输出示例:```
Parsed Key-ValuePairs:
"Comments"=>"SN215U0540""Company"=>"******""InstrumentS/N"=>"09-113-0519""MeasureProgram"=>"MTFvs.Field vs. Focus"
"Measuredwith"=>"TRIOPTICS- MT=\nF-LAB -Vers.5.16.1"
"Operator"=>"******"
"Sample ID"=>"******""Temperature"=>"20°C"
"Time/Date"=>"13:41:21June12,2025"```
注意:`"Measuredwith"`的值包含换行符,因此显示为两行(在qDebug输出中,换行符会显示为`\n`)。
###改进点:
-如果值中的换行符不需要,可以用空格代替(将`currentValue +="\n" +line.trimmed();`改为`currentValue +=" "+ line.trimmed();`)
-如果键的顺序很重要,可以用`QList<QPair<QString,QString>>`代替`QMap`(因为`QMap`会按键排序)§§相关问题§§:
1.如何修改代码以保留键值对的原始顺序(不使用QMap)?
2.如果值部分包含转义冒号(例如使用反斜杠),应如何处理?3.如何将解析后的键值对写入到JSON文件中?4.如果原始数据中键包含空格(如"Instrument S/N"),如何避免在trimmed()时丢失空格?</think>以下是用 Qt C++ 实现的解决方案,专门处理带有固定格式的文本数据,避免因值中包含换行符导致的分割问题:
```cpp
#include <QCoreApplication>
#include <QString>
#include <QStringList>
#include <QMap>
#include <QDebug>
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
// 原始字符串(包含值中的换行符)
QString data =
"Company : ******\n"
"Operator : ******\n"
"Time/Date : 13:41:21 June 12, 2025\n"
"Sample ID : ******\n"
"Measure Program : MTF vs. Field vs. Focus\n"
"Temperature : 20°C\n"
"Measured with : TRIOPTICS - MT=\n" // 注意这里值包含换行符
"F-LAB - Vers. 5.16.1\n" // 这是上一行值的延续
"Instrument S/N : 09-113-0519\n"
"Comments : SN215U0540";
// 步骤1: 按行分割,但保留换行符
QStringList lines = data.split('\n');
// 步骤2: 合并被错误分割的值行
QStringList mergedLines;
QString currentLine;
for (const QString& line : lines) {
// 检查是否是新的键值对(包含冒号且冒号前没有等号)
if (line.contains(':') && !line.split(':').first().contains('=')) {
if (!currentLine.isEmpty()) {
mergedLines.append(currentLine.trimmed());
currentLine.clear();
}
currentLine = line;
} else {
// 值续行(添加到当前行)
if (!currentLine.isEmpty()) {
currentLine += " " + line; // 用空格连接续行
}
}
}
if (!currentLine.isEmpty()) {
mergedLines.append(currentLine.trimmed());
}
// 步骤3: 解析键值对
QMap<QString, QString> resultMap;
for (const QString& line : mergedLines) {
int colonIndex = line.indexOf(':');
if (colonIndex != -1) {
QString key = line.left(colonIndex).trimmed();
QString value = line.mid(colonIndex + 1).trimmed();
resultMap[key] = value;
}
}
// 步骤4: 输出结果
qDebug() << "Parsed Key-Value Pairs:";
for (auto it = resultMap.constBegin(); it != resultMap.constEnd(); ++it) {
qDebug() << it.key() << "=>" << it.value();
}
return a.exec();
}
```
### 代码解释:
1. **问题分析**:
- 原始数据中 `Measured with` 的值包含换行符和等号,导致简单使用 `split('\n')` 会错误分割
- 键总是以冒号结尾,且冒号前不会包含等号(`=`)
- 值续行不包含冒号,且缩进与键不同
2. **合并续行**:
```cpp
QStringList mergedLines;
QString currentLine;
for (const QString& line : lines) {
if (line.contains(':') && !line.split(':').first().contains('=')) {
if (!currentLine.isEmpty()) {
mergedLines.append(currentLine.trimmed());
currentLine.clear();
}
currentLine = line;
} else {
if (!currentLine.isEmpty()) {
currentLine += " " + line; // 用空格连接续行
}
}
}
```
- 识别真正的键行(包含冒号且冒号前无等号)
- 将续行(不含冒号)附加到当前值
- 用空格连接续行,保持值的连贯性
3. **键值解析**:
```cpp
for (const QString& line : mergedLines) {
int colonIndex = line.indexOf(':');
if (colonIndex != -1) {
QString key = line.left(colonIndex).trimmed();
QString value = line.mid(colonIndex + 1).trimmed();
resultMap[key] = value;
}
}
```
- 使用首个冒号作为分隔符
- `trimmed()` 移除键/值两端的空白字符
4. **输出示例**:
```
Parsed Key-Value Pairs:
"Comments" => "SN215U0540"
"Company" => "******"
"Instrument S/N" => "09-113-0519"
"Measure Program" => "MTF vs. Field vs. Focus"
"Measured with" => "TRIOPTICS - MT= F-LAB - Vers. 5.16.1"
"Operator" => "******"
"Sample ID" => "******"
"Temperature" => "20°C"
"Time/Date" => "13:41:21 June 12, 2025"
```
- 注意 `Measured with` 的值已正确合并
### 关键改进:
1. **智能行合并**:
- 通过检查冒号和等号的位置区分键行和值续行
- 保留原始值中的换行信息,同时确保正确解析
2. **空白处理**:
- 使用 `trimmed()` 消除键/值两端的空格
- 续行连接时添加空格,避免单词粘连
3. **数据结构**:
- `QMap<QString, QString>` 自动按键排序
- 提供高效的键值查找能力
阅读全文
相关推荐


















