如何从ifstream获取格式化的输入
How to take formatted input from ifstream
我有一个文本文件,其中包含一组按以下方式格式化的名称:
"MARY","PATRICIA","LINDA","BARBARA","ELIZABETH"
等等。我想使用ifstream打开文件,并将名称读入字符串数组(不带引号,逗号)。我设法通过逐个字符检查输入流来做到这一点。是否有一种更简单的方法来接受这种格式化的输入?
编辑:我听说你可以用fscanf (f, ""%[a-zA-Z]",", str);在C,但有这样的方法ifstream?
该输入应该可以用std::getline
或std::regex_token_iterator
进行解析(尽管后者是用大炮射击麻雀)。
例子:
<标题> Regex h1> strong>快速和肮脏,但重量级的解决方案(使用boost,所以大多数编译器吃这个)
#include <boost/regex.hpp>
#include <iostream>
int main() {
const std::string s = ""MARY","PATRICIA","LINDA","BARBARA","ELIZABETH"";
boost::regex re(""(.*?)"");
for (boost::sregex_token_iterator it(s.begin(), s.end(), re, 1), end;
it != end; ++it)
{
std::cout << *it << std::endl;
}
}
输出:MARY
PATRICIA
LINDA
BARBARA
ELIZABETH
或者,您可以使用
boost::regex re(",");
for (boost::sregex_token_iterator it(s.begin(), s.end(), re, -1), end;
让它沿着逗号(也注意-1)或其他正则表达式分开。
<标题> getline h1> strong>
getline
solution(允许有空格)
#include <sstream>
#include <iostream>
int main() {
std::stringstream ss;
ss.str (""MARY","PATRICIA","LINDA","BARBARA","ELIZABETH"");
std::string curr;
while (std::getline (ss, curr, ',')) {
size_t from = 1 + curr.find_first_of ('"'),
to = curr.find_last_of ('"');
std::cout << curr.substr (from, to-from) << std::endl;
}
}
输出相同
<标题> getline h1> strong>
getline
solution(不允许空格)
循环几乎变得微不足道:
std::string curr;
while (std::getline (ss, curr, ',')) {
std::cout << curr.substr (1, curr.length()-2) << std::endl;
}
<标题>自制程序解决方案
最不浪费w.r.t.性能(特别是当您不存储这些字符串,而是存储迭代器或索引时)
#include <iostream>
int main() {
const std::string str (""MARY","PATRICIA","LINDA","BARBARA","ELIZABETH"");
size_t i = 0;
while (i != std::string::npos) {
size_t begin = str.find ('"', i) + 1, // one behind initial '"'
end = str.find ('"', begin),
comma = str.find (',', end);
i = comma;
std::cout << str.substr(begin, end-begin) << std::endl;
}
}
标题>标题>标题>标题>
据我所知,STL中没有标记器。但如果你愿意使用boost,那里有一个非常好的标记器类。除此之外,逐个字符是您最好的c++寻址方式(除非您愿意走C路线,并在原始char *
字符串上使用strtok_t
)。
一个简单的标记器就可以做到;不需要像正则表达式这样重量级的东西。c++没有内置的,但是很容易编写。这是我自己很久以前从网上偷来的,我甚至不记得是谁写的,所以为公然抄袭道歉:
#include <vector>
#include <string>
std::vector<std::string>
tokenize(const std::string & str, const std::string & delimiters)
{
std::vector<std::string> tokens;
// Skip delimiters at beginning.
std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
// Find first "non-delimiter".
std::string::size_type pos = str.find_first_of(delimiters, lastPos);
while (std::string::npos != pos || std::string::npos != lastPos)
{
// Found a token, add it to the vector.
tokens.push_back(str.substr(lastPos, pos - lastPos));
// Skip delimiters. Note the "not_of"
lastPos = str.find_first_not_of(delimiters, pos);
// Find next "non-delimiter"
pos = str.find_first_of(delimiters, lastPos);
}
return tokens;
}
用法:std::vector<std::string> words = tokenize(line, ",");
实际上,因为我很感兴趣,我研究了如何使用Boost.Spirit.Qi
:
#include <boost/spirit/include/qi.hpp>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace boost::spirit::qi;
int main() {
// our test-string
std::string data(""MARY","PATRICIA","LINDA","BARBARA"");
// this is where we will store the names
std::vector<std::string> names;
// parse the string
phrase_parse(data.begin(), data.end(),
( lexeme['"' >> +(char_ - '"') >> '"'] % ',' ),
space, names);
// print what we have parsed
std::copy(names.begin(), names.end(),
std::ostream_iterator<std::string>(std::cout, "n"));
}
要检查解析过程中是否发生错误,只需将字符串上的迭代器存储在变量中,然后比较它们。如果它们相等,则匹配整个字符串,否则,begin-迭代器将指向错误位置。
相关文章:
- 从格式化输入操作中获取读取字符数
- 如何从标准输入中检测格式化输入错误?
- 如何读取和处理格式化的日期,如 01/11/1998、星期日(10000 个输入)C++
- 是否可以使用一行代码从 std::cin 中提取格式化输入
- 在列中格式化输出(用户输入)
- 如何读取时间输入并格式化输出
- 未格式化/格式化的输入
- 如何格式化重载的 c++ 输入运算符
- 在C++中解析格式化的用户输入
- 解析格式化输入时划分单词时出现问题
- 如何使用 getline 和字符串流来解析格式化的日期和时间输入
- std::getline()从流中读取格式化的输入后读取错误的数据
- 来自 std::vector <double>的未格式化流输入
- 使用cin读取格式化输入
- 如何确定未格式化输入函数读取的字符数
- 正在重新格式化输入的带有空格的字符串
- 扫描 读取格式化输入
- c++中字符串的格式化输入
- 在c++中从格式化输入切换到非格式化输入
- 格式化输入 - scanf 的C++版本是什么?