1

我一直在尝试制作一个解析文本文件并将信息6片段输入对象数组的程序。对我来说,问题是我在弄清楚如何处理文本文件时遇到了问题。有人告诉我,我需要做的第一步是编写一些代码来计算每个条目的长度。txt文件格式如下:

"thing1","thing2","thing3","thing4","thing5","thing6"

这是我的代码的当前版本:

#include<iostream>
#include<string>
#include<fstream>
#include<cstring>

using namespace std;

int main()
{
ifstream myFile("Book List.txt");

while(myFile.good())
{
    string line;

    getline(myFile, line);

    char *sArr = new char[line.length() + 1];
    strcpy(sArr, line.c_str());

    char *sPtr;

    sPtr = strtok(sArr, " ");

    while(sPtr != NULL)
    {
        cout << strlen(sPtr) << " ";
        sPtr = strtok(NULL, " ");
    }
    cout  << endl;
}
myFile.close();
return 0;
}

所以有两件事让我现在很难。

1)如何处理分隔符?

2)如何处理“跳过”每行中的第一个引号?

4

3 回答 3

1

如果你必须使用,strtok那么这个代码片段应该足以修改你的程序来解析你的数据:

#include <cstdio>
#include <cstring>

int main ()
{
  char str[] ="\"thing1\",\"thing2\",\"thing3\",\"thing4\",\"thing5\"";
  char * pch;
  printf ("Splitting string \"%s\" into tokens:\n",str);
  pch = strtok (str,"\",");
  while (pch != NULL)
  {
    printf ("%s\n",pch);
    pch = strtok (NULL, ",\"");
  }
  return 0;
}

如果您不必使用,strtok那么您应该std::string按照其他人的建议使用。使用std::stringstd::istringstream

#include <string>
#include <sstream>
#include <vector>
#include <iostream>

int main ()
{
  std::string str2( "\"thing1\",\"thing2\",\"thing3\",\"thing4\",\"thing5\"" ) ;

  std::istringstream is(str2);
  std::string part;

  while (getline(is, part, ','))
     std::cout << part.substr(1,part.length()-2) << std::endl;

  return 0;
}
于 2013-04-30T02:06:55.793 回答
1

strtok对于初学者,如果可以避免,请不要使用(您可以在这里轻松地 - 您甚至可以避免使用这一find系列功能)。

如果您想阅读整行然后解析它:

#include <algorithm>
#include <iostream>
#include <iterator>
#include <sstream>
#include <string>
#include <vector>

// defines a new ctype that treats commas as whitespace
struct csv_reader : std::ctype<char>
{
    csv_reader() : std::ctype<char>(get_table()) {}

    static std::ctype_base::mask const* get_table()
    {
        static std::vector<std::ctype_base::mask> rc(table_size, std::ctype_base::mask());
        rc['\n'] = std::ctype_base::space;
        rc[','] = std::ctype_base::space;
        return &rc[0];
    }
};

int main()
{
    std::ifstream fin("yourFile.txt");
    std::string line;
    csv_reader csv;
    std::vector<std::vector<std::string>> values;
    while (std::getline(fin, line))
    {
        istringstream iss(line);
        iss.imbue(std::locale(std::locale(), csv));
        std::vector<std::string> vec;
        std::copy(std::istream_iterator<std::string>(iss), std::istream_iterator<std::string>(), std::back_inserter(vec));
        values.push_back(vec);
    }
    // values now contains a vector for each line that has the strings split by their commas
    fin.close();
    return 0;
}

这回答了你的第一个问题。对于您的第二个,您可以通过将它们添加到掩码来跳过所有引号rc(也将它们视为空格),或者您可以在之后将它们删除(直接或使用 a transform):

std::transform(vec.begin(), vec.end(), vec.begin(), [](std::string& s)
{
    std::string::iterator pend = std::remove_if(s.begin(), s.end(), [](char c)
    {
        return c == '"';
    });
    s.erase(pend, s.end());
});
于 2013-10-05T02:36:04.743 回答
1

读入字符串而不是 c 样式的字符串。这意味着您可以使用方便的 std 方法。

std::string::find()方法应该可以帮助您找到要解析的每一件事。

http://www.cplusplus.com/reference/string/string/find/

您可以使用它来查找所有逗号,这将为您提供所有事物的开头。

然后你可以用std::string::substr()把绳子剪成每一块。

http://www.cplusplus.com/reference/string/string/substr/

您可以通过传递比开始多 1 和比事物长度少 1 来设法摆脱引号,您也可以使用

于 2013-04-30T01:57:37.093 回答