C ++文件转换:竖线分隔为逗号分隔

问题描述 投票:0回答:1

我正在尝试找出如何将管道分隔形式的输入文件转换为逗号分隔。我必须打开文件,将其读取到数组中,将其转换为以逗号分隔的输出CSV文件,然后关闭所有文件。有人告诉我,最简单的方法是在excel内,但我不确定如何做到。

#include <iostream>
#include <fstream>
using namespace std;

int main()
{
    ifstream inFile;
    string myArray[5];

  cout << "Enter the input filename:";
   cin >> inFileName;

    inFile.open(inFileName);
    if(inFile.is_open())
    std::cout<<"File Opened"<<std::endl;

// read file line by line into array
    cout<<"Read";

     for(int i = 0; i < 5; ++i)
     {
       file >> myArray[i];
        }

//文件转换

// close input file
   inFile.close();

//关闭输出文件outFile.close();

我需要转换的是:

每小时英里| 6,445 |成为“第二”团队| 5.54 | 9.98 | 6,555.00“结局”游戏|离开“开始” |新泽西州伊丽莎白| 25.25 | 6.78 | 987.01|在晚上或白天结束|“我们走吧” | 65,978.21 | 0.00 | 123.45左基夜| 10/07/1900 ||| 4.07 | 777.23“让我们开始吧” |开始棒球比赛|开始新游戏赢球

输出应该以逗号分隔的形式:

每小时英里,“ 6,445”,“成为”“第二”“团队成员”,5.54,9.98,“ 6,555.00”,“”“”结局“”游戏“,”在“”开始“,”“,”科罗拉多州丹佛“左侧,,“白天晚上结束”,“”“我们走吧”,“”,“ 65,978.21”,0.00、123.45,左基夜,10/07/1900 ,,, 4.07,777.23,“”“让我们开始吧”“”“,开始棒球比赛,开始新的比赛,

c++ xcode file-conversion
1个回答
0
投票

我将向您展示完整的解决方案并向您解释。但首先让我们对其进行查看:

#include <iostream>
#include <vector>
#include <fstream>
#include <regex>
#include <string>
#include <algorithm>

// I omit the example here for inputting the filenames. This exercise can be done by somebody else
// Use fixed filenames in this example.
const std::string inputFileName("r:\\input.txt");
const std::string outputFileName("r:\\output.txt");

// The delimiter for the source csv file
std::regex re{ R"(\|)" };

std::string addQuotes(const std::string& s) {
    // if there are single quotes in the string, then replace them with double quotes
    std::string result = std::regex_replace(s, std::regex(R"(")"), R"("")");

    // If there is any quote (") or comma in the file, then quote the complete string
    if (std::any_of(result.begin(), result.end(), [](const char c) { return ((c == '\"') || (c == ',')); })) {
        result = "\"" + result + "\"";
    }
    return result;
}


// Some output function
void printData(std::vector<std::vector<std::string>>& v, std::ostream& os) {
    // Go throug all rows
    std::for_each(v.begin(), v.end(), [&os](const std::vector<std::string>& vs) {
        // Define delimiter
        std::string delimiter{ "" };
        // Show the delimited strings
        for (const std::string& s : vs) {
            os << delimiter << s;
            delimiter = ",";
        }
        os << "\n";
    });
}

int main() {


    // We first open the ouput file, becuse, if this cannot be opened, then no meaning to do the rest of the exercise
    // Open output file and check, if it could be opened
    if (std::ofstream outputFileStream(outputFileName); outputFileStream) {

        // Open the input file and check, if it could be opened
        if (std::ifstream inputFileStream(inputFileName); inputFileStream) {

            // In this variable we will store all lines from the CSV file including the splitted up columns
            std::vector<std::vector<std::string>> data{};

            // Now read all lines of the CSV file and split it into tokens
            for (std::string line{}; std::getline(inputFileStream, line); ) {

                // Split line into tokens and add to our resulting data vector
                data.emplace_back(std::vector<std::string>(std::sregex_token_iterator(line.begin(), line.end(), re, -1), {}));
            }
            std::for_each(data.begin(), data.end(), [](std::vector<std::string>& vs) {
                std::transform(vs.begin(), vs.end(), vs.begin(), addQuotes);
            });

            // Output, to file
            printData(data, outputFileStream);

            // And to the screen
            printData(data, std::cout);
        }
        else {
            std::cerr << "\n*** Error: could not open input file '" << outputFileName << "'\n";
        }

    }
    else {
        std::cerr << "\n*** Error: could not open output file '" << outputFileName << "'\n";
    }
    return 0;
}

所以,让我们看看。我们有功能

  • [main,读取csv文件,将其拆分为令牌,对其进行转换,然后将其写入]
  • addQuotes。如有必要,添加报价
  • [printData打印他已将数据转换为输出流

让我们从main开始。 main将首先打开输入文件和输出文件。

输入文件具有结构化数据的类型,也称为csv(逗号分隔值)。但是在这里,我们没有逗号,而是用竖线符号代替。

并且结果将通常存储在二维向量中。在维度1中为行,在其他维度中为列。

所以,接下来我们需要做什么?如我们所见,我们需要首先阅读源流中所有完整的文本行。一线即可轻松完成:

for (std::string line{}; std::getline(inputFileStream, line); ) {

如您所见,here,for语句具有声明/初始化部分,然后是条件,然后是在循环末尾执行的语句。这是众所周知的。

我们首先定义类型为std::string的变量“行”,并使用默认的初始化程序创建一个空字符串。然后,我们使用std::getline从流中读取整行并将其放入变量中。 std::getline返回对sthe流的引用,并且该流具有重载的bool运算符,如果发生故障(或文件结尾),它将在此返回。因此,for循环不需要对文件末尾进行额外检查。而且我们不使用for循环的最后一条语句,因为通过读取一行,文件指针会自动前进。

这为我们提供了一个非常简单的for循环,可以逐行读取完整的文件。

请注意:在for循环中定义变量“ line”,将其范围限定为for循环。这意味着,它仅在for循环中可见。通常,这是防止污染外部名称空间的好方法。

确定,现在下一行:

data.emplace_back(std::vector<std::string>(std::sregex_token_iterator(line.begin(), line.end(), digit), {}));

哦,那是什么?

[好,逐步进行。首先,我们显然想在二维数据向量上添加一些东西。我们将使用std::vector的功能emplace_back。我们本来可以使用push_back,但这意味着我们需要进行不必要的数据复制。因此,我们选择emplace_back对要添加到二维数据向量中的对象进行就地构造。

我们要添加什么?我们要添加完整的行,因此要添加列向量。在我们的例子中是std::vector<std::string>。并且,由于我们要在此向量中进行就地构造,因此我们将其称为向量范围构造函数。请在这里查看:Constructor number 5。范围构造函数将2个迭代器(一个开始迭代器和一个结束迭代器)作为参数,并将迭代器指向的所有值复制到向量中。]

因此,我们期望一个开始和结束迭代器。我们在这里看到什么:

  • 开始迭代器为:std::sregex_token_iterator(line.begin(), line.end(), digit)
  • 并且最终迭代器就是{}
  • 但是这是什么,sregex_token_iterator

    这是一个迭代器,它迭代一行中的模式。模式由regex给出。您可以阅读有关C ++ regex libraray的here。由于它非常强大,因此不幸的是您需要学习一些时间。我不能在这里介绍它。但是让我们来描述其基本功能以达到我们的目的:您可以用某种元语言来描述模式,std::sregex_token_iterator将查找该模式,如果找到匹配的模式,则返回相关数据。在我们的例子中,模式非常简单:数字。可以用“ \ d +”来表示,这意味着尝试匹配一个或多个数字。

现在作为{}作为结束迭代器。您可能已经读到{}将进行默认的构造/初始化。而且,如果您阅读here, number 1,则会看到“默认构造函数”构造了一个序列结束迭代器。因此,正是我们需要的。


读取完所有数据后,我们会将单个字符串转换为所需的输出。这将通过std::transform和功能addQuotes完成。这里的策略是首先用双引号替换单引号。

然后,接下来,我们查看字符串中是否包含逗号或引号,然后将整个字符串另外用引号引起来。

最后,但并非最不重要的一点,我们有一个简单的输出功能,并将转换后的数据打印到文件中并在屏幕上显示。

© www.soinside.com 2019 - 2024. All rights reserved.