如何在 C++ 程序中的 2 个特定字符之间比较 2 个文件中的文本行
Posted
技术标签:
【中文标题】如何在 C++ 程序中的 2 个特定字符之间比较 2 个文件中的文本行【英文标题】:How do I compare text lines in 2 files between 2 specific characters in a C++ program 【发布时间】:2020-12-17 23:30:32 【问题描述】:我正在编写这个程序,它清理 xml 文件并将新行从 txt 文件添加到设置部分。其中一部分我的代码中有一个标记为 // 部分的部分。在该部分期间或之后,都可以,我想比较这些行以确保它们没有重复,但在这种情况下忽略它们的设置 True 和 False 并且如果一个设置为 true 而另一个设置为则认为它们相同为假,只保留第二行并丢弃第一行。以下是设置外观的示例:
<setting1>true</setting1>
<setting2blue>false</setting2blue>
<setting3>true</setting3>
<setting1>false</setting1>
<setting4>true</setting4>
<setting2blue>true</setting2blue>
所以最后我希望删除第一个设置 1,保留第二个设置 1,设置 2 也一样。请记住,这是一个示例,因为设置有不同的名称,有时包含相同的单词.
我曾尝试使用 .compare,但由于我对 C++ 还很陌生,所以我真的迷路了。即使我可能需要做一个新的输入流和输出流,然后在我之前的工作完成后进行比较,但我仍然对如何比较感到困惑。
感谢您的帮助。
谢谢, 仇杀
这是我无需运行整个程序即可进行测试的程序的一部分。
#include <stdio.h>
#include <fstream>
#include <sstream>
#include <iostream>
#include <string>
#include <cctype>
#include <cstdlib>
#include <set>
#include <vector>
#include <algorithm>
#include <cassert>
#include <Windows.h>
using namespace std;
bool isSpace(unsigned char c)
return ( c == '\r' ||
c == '\t' || c == '\v' || c == '\f');
int main()
const string Dir "C:/synergyii/config/" ;
ifstream in_config Dir + "clientconfig.xml" ,
in_newlines Dir + "newlines.txt" ;
ofstream out Dir + "cltesting.txt" ;
vector<string> vlines31;
vector<string> vlines32;
set<string> slines31;
set<string> slines32;
for (string line31; getline(in_config, line31); vlines31.push_back(line31))
if (line31.find("<settings>") != string::npos)
vlines31.push_back(line31);
break;
for (const auto& v : vlines31)
out << v << '\n';
// <settings> Part
for (string line32; getline(in_config, line32) && line32.find("</settings>") == string::npos; )
line32.erase(remove_if(line32.begin(), line32.end(), isSpace), line32.end());
line32.erase(line32.find_last_not_of(" ") + 1);
const auto& result = slines32.insert(line32);
if (result.second)
vlines32.push_back(line32);
for (string line32; getline(in_newlines, line32);)
line32.erase(remove_if(line32.begin(), line32.end(), isSpace), line32.end());
const auto& result = slines32.insert(line32);
if (result.second)
vlines32.push_back(line32);
vlines32.erase(unique(vlines32.begin(), vlines32.end()), vlines32.end() );
for (auto it = vlines32.cbegin(); it != vlines32.cend(); ++it)
out << '\t' << '\t' << *it << '\n';
out << '\t' << "</settings>\n";
out << "</config>\n";
in_config.close();
out.close();
【问题讨论】:
【参考方案1】:关于 XML 先的说明:
XML 允许格式化,但不一定会改变其内容的含义。除了缩进之外,一个元素可以写在一行中,也可以分布在多行中。甚至允许将整个 XML 文件写入一行(假设元素内容中没有换行符,就像 OP 一样)。
使用 C++ 标准 I/O 正确读取 XML 比几个 std::getline()
s 更复杂。要做到这一点,应该使用 XML 库将 XML 文件读入 DOM 以进行预期的处理。
例如。 SO: What XML parser should I use in C++? 提供有关可用 XML 库的概述。
话虽如此,我想为 OPs 问题演示一个可能的解决方案,但使用另一个更简单的配置。格式 – 以冒号分隔的键值对 (:
)。
如何过滤掉重复的键:
解决方案其实很简单:
整个文件逐行读取到vector
的string
s。
如果一行包含一个键,则该键存储在查找表中。
如果该键已经在该查找表中,则先前的出现(行)被标记为无效。为了简单起见,我只是清除了界限。如果空行可能是有效内容(应保存在文件中),则应使用其他内容来标记该行,例如每行存储一个额外的bool
。
我没有考虑删除行作为一个选项,因为这会使存储的所有键的行索引无效(或者我必须遍历查找表来修复它们)。
演示:
#include <iostream>
#include <map>
#include <sstream>
#include <string>
#include <vector>
std::vector<std::string> lines;
using LookUpTable = std::map<std::string, size_t>;
LookUpTable lut;
std::istream& readLine(std::istream &in)
std::string line; if (!std::getline(in, line)) return in;
const size_t iLine = lines.size();
// extract key
const size_t i = line.find(':');
if (i < line.size()) // Has the line a key at all?
std::string key = line.substr(0, i);
// look whether there was already this setting
const LookUpTable::iterator iter = lut.find(key);
if (iter != lut.end()) // Was it already there?
// clear previous line
lines[iter->second].clear();
// store key and line index
lut.emplace(std::move(key), iLine);
// store line in lines buffer
lines.push_back(std::move(line));
// done
return in;
void readFile(std::istream &in)
while (readLine(in));
void writeFile(std::ostream &out)
for (const std::string line : lines)
// skip empty lines
if (line.empty()) continue;
// write non-empty lines
out << line << '\n';
int main()
std::string sample = R"(# sample config file
setting1: true
setting2blue: false
setting3: true
setting1: false
setting4: true
setting2blue: true
)";
// read the sample
std::istringstream in(sample);
readFile(in);
// write the sample (with clean-up)
std::cout << "Output:\n";
writeFile(std::cout);
输出:
Config.:
# sample config file
setting3: true
setting1: false
setting4: true
setting2blue: true
Live Demo on coliru
挑剔:
无序地图可能提供比地图更快的查找速度。它可能会为此付出更高的内存占用。我怀疑这种差异对于这项任务来说是必不可少的,但只需稍加改动,它也可以与 unordered_map
一起使用:
Live Demo on coliru
【讨论】:
以上是关于如何在 C++ 程序中的 2 个特定字符之间比较 2 个文件中的文本行的主要内容,如果未能解决你的问题,请参考以下文章
如何从 C++ 中的 getline 函数中提取特定的子字符串?
如何比较给定时间,落在特定时间范围之间 - javascript