【问题标题】:C++ - string.compare issues when output to text file is different to console output?C++ - 当输出到文本文件与控制台输出不同时出现 string.compare 问题?
【发布时间】:2009-11-19 09:36:20
【问题描述】:

出于单元测试的目的,我试图找出我拥有的两个字符串是否相同。第一个是预定义的字符串,硬编码到程序中。第二个是使用 std::getline() 从带有 ifstream 的文本文件中读取,然后将其作为子字符串。这两个值都存储为 C++ 字符串。

当我使用 cout 将两个字符串输出到控制台进行测试时,它们看起来都是相同的:

ThisIsATestStringOutputtedToAFile ThisIsATestStringOutputtedToAFile

但是,string.compare 返回表明它们不相等。输出到文本文件时,两个字符串如下所示:

ThisIsATestStringOutputtedToAFile T^@h^@i^@s^@I^@s^@A^@T^@e^@s^@t^@S^@t^@r^@i^@n^@g^ @O^@u^@t^@p^@u^@t^@ t^@e^@d^@T^@o^@A^@F^@i^@l^@e

我猜这是某种编码问题,如果我使用的是我的母语(好旧的 C#),我不会有太多问题。因为它是 C/C++ 和 Vi,坦率地说,我真的不知道从这里去哪里!我已经尝试查看可能转换为/从 ansi/unicode 转换,还删除了奇怪的字符,但我什至不确定它们是否真的存在..

提前感谢您的任何建议。

编辑 抱歉,这是我第一次在这里发帖。下面的代码是我正在经历的过程:

ifstream myInput;
ofstream myOutput;

myInput.open(fileLocation.c_str()); 
myOutput.open("test.txt");

TEST_ASSERT(myInput.is_open() == 1);

string compare1 = "ThisIsATestStringOutputtedToAFile";
string fileBuffer;

std::getline(myInput, fileBuffer);
string compare2 = fileBuffer.substr(400,100);

cout << compare1 + "\n";
cout << compare2 + "\n";
myOutput << compare1 + "\n";
myOutput << compare2 + "\n";
cin.get();

myInput.close();
myOutput.close();

TEST_ASSERT(compare1.compare(compare2) == 0);

【问题讨论】:

  • 看起来你的第二个字符串是 2byte unicode?​​span>
  • 您需要告诉我们字符串的确切类型、输出方式以及比较方式 - 请在代码中。

标签: c++ string compare


【解决方案1】:

您是如何创建myInput 的内容的?我猜这个文件是用两字节编码创建的。你可以使用 hex-dump 来验证这个理论,或者使用不同的编辑器来创建这个文件。

最简单的方法是启动 cmd.exe 并输入

echo "ThisIsATestStringOutputtedToAFile" &gt; test.txt

更新:

如果您无法更改myInput 文件的编码,您可以尝试在程序中使用宽字符。 IE。用wstring代替stringwifstream代替ifstreamwofstreamwcout

【讨论】:

  • myInput 的内容是一个自定义文件扩展名 XML 文件,尽管用 vi 打开它们会显示它被识别为二​​进制文件。逐行读取文件并将其打印到控制台显示它很好,所以我猜我需要将它从二进制流转换为 ACSII 类型流?
  • 当您将文件打印到控制台时,ASCII 码低于 32 的字符被视为控制码(例如 TAB、CR、LF 等)。字符 ^@ (ASCII 0x00) 没有任何作用,它只是被跳过。由于这些 ^@ 字符,Vi 将文件识别为二进制文件。
  • myInput 文件似乎是二进制格式。更多的搜索导致了这篇文章,这让我在我的道路上做得很好。为帮助干杯! stackoverflow.com/questions/181634/…
【解决方案2】:

以下内容对我有用,并将下面粘贴的文本写入文件。注意嵌入到字符串中的'\0' 字符。

#include <iostream>
#include <fstream>
#include <sstream>

int main()
{
    std::istringstream myInput("0123456789ThisIsATestStringOutputtedToAFile\x0 12ou 9 21 3r8f8 reohb jfbhv jshdbv coerbgf vibdfjchbv jdfhbv jdfhbvg jhbdfejh vbfjdsb vjdfvb jfvfdhjs jfhbsd jkefhsv gjhvbdfsjh jdsfhb vjhdfbs vjhdsfg kbhjsadlj bckslASB VBAK VKLFB VLHBFDSL VHBDFSLHVGFDJSHBVG LFS1BDV LH1BJDFLV HBDSH VBLDFSHB VGLDFKHB KAPBLKFBSV LFHBV YBlkjb dflkvb sfvbsljbv sldb fvlfs1hbd vljkh1ykcvb skdfbv nkldsbf vsgdb lkjhbsgd lkdcfb vlkbsdc xlkvbxkclbklxcbv");
    std::ofstream myOutput("test.txt");
    //std::ostringstream myOutput;

    std::string str1 = "ThisIsATestStringOutputtedToAFile";
    std::string fileBuffer;

    std::getline(myInput, fileBuffer);
    std::string str2 = fileBuffer.substr(10,100);

    std::cout << str1 + "\n";
    std::cout << str2 + "\n";
    myOutput << str1 + "\n";
    myOutput << str2 + "\n";

    std::cout << str1.compare(str2) << '\n';

    //std::cout << myOutput.str() << '\n';
    return 0;
}

输出:

ThisIsATestStringOutputtedToAFile ThisIsATestStringOutputtedToAFile

【讨论】:

    【解决方案3】:

    原来问题在于 myInput 的文件编码是 UTF-16,而比较字符串是 UTF-8。使用该项目的操作系统限制(Linux、C/C++ 代码)转换它们的方法是使用 iconv() 函数。为了保持我一直使用的 C++ 字符串的兼容性,我最终将字符串保存到一个新的文本文件中,然后通过 system() 命令运行 iconv。

    system("iconv -f UTF-16 -t UTF-8 subStr.txt -o convertedSubStr.txt");
    

    重新读取输出的字符串,然后以我需要的格式为我提供了比较正常工作的字符串。

    注意 我知道这不是最有效的方法。我已经拥有了 Windows 环境和 windows.h 库的奢侈,事情会容易得多。但在这种情况下,代码在一些很少使用的单元测试中,因此不需要高度优化,因此某些文本文件的创建、销毁和 I/O 操作不是问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-27
      相关资源
      最近更新 更多