如何从ifstream获取格式化的输入

How to take formatted input from ifstream

本文关键字:格式化 输入 获取 ifstream      更新时间:2023-10-16

我有一个文本文件,其中包含一组按以下方式格式化的名称:

"MARY","PATRICIA","LINDA","BARBARA","ELIZABETH"

等等。我想使用ifstream打开文件,并将名称读入字符串数组(不带引号,逗号)。我设法通过逐个字符检查输入流来做到这一点。是否有一种更简单的方法来接受这种格式化的输入?

编辑:我听说你可以用fscanf (f, ""%[a-zA-Z]",", str);在C,但有这样的方法ifstream?

该输入应该可以用std::getlinestd::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-迭代器将指向错误位置。