如何在 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 问题演示一个可能的解决方案,但使用另一个更简单的配置。格式 – 以冒号分隔的键值对 (:)。

如何过滤掉重复的键:

解决方案其实很简单: 整个文件逐行读取到vectorstrings。 如果一行包含一个键,则该键存储在查找表中。 如果该键已经在该查找表中,则先前的出现(行)被标记为无效。为了简单起见,我只是清除了界限。如果空行可能是有效内容(应保存在文件中),则应使用其他内容来标记该行,例如每行存储一个额外的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 函数中提取特定的子字符串?

比较C中两个字符串的每个字符

如何比较给定时间,落在特定时间范围之间 - javascript

c语言编写一个程序,实现查找一个字符串中的特定字符,并将其删除.

如何使用 C++ 写入文件的特定列?

如何使用 QTcpSocket 监听 qt 中的特定端口? [复制]