我一直在努力创建一个解析文本文件的程序,并将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)我如何处理“跳过”每行中的第一个引号?
答案 0 :(得分: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个小于事物的长度来摆脱引号,你也可以使用
答案 1 :(得分: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::string
和std::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;
}
答案 2 :(得分: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
掩码(也将它们视为空格)来跳过所有引号,或者之后可以将它们删除(直接或使用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());
});