将多个单词提取到一个字符串变量

时间:2010-01-22 17:19:04

标签: c++ string stringstream

std::stringstream convertor("Tom Scott 25");
std::string name;   
int age;

convertor >> name >> age;

if(convertor.fail())
{
    // it fails of course
}

我想将两个或多个单词提取到一个字符串变量中。到目前为止,我已经读过,似乎不可能。如果是这样,怎么办呢?我希望name在数字(年龄)之前获取所有字符。

我觉得使用sscanf最舒服,但我显然不能。

我需要的是能够在age之前提取所有字词。

8 个答案:

答案 0 :(得分:3)

这有什么问题?

std::stringstream convertor("Tom Scott 25");
std::string firstname;   
std::string surname;
int age;

convertor >> firstname >> surname >> age;
std::string name = firstname + " " + surname;

答案 1 :(得分:3)

到目前为止发布的大多数解决方案都不符合规范 - 所有截至年龄的数据都被视为名称。例如,他们会以“Richard Van De Rothstyne”这样的名字失败。

正如OP所指出的那样,使用scanf,您可以执行以下操作:scanf("%[^0-9] %d", name, &age);,它会很好地读取它。假设这是面向行的输入,我倾向于这样做:

std::string temp;
std::getline(infile, temp);

// technically "[^0-9]" isn't required to work right...
sscanf(temp.c_str(), "%[^0123456789] %d", name, &age);

不幸的是,iostream并不直接模拟扫描集转换 - getline可以读取分隔符,但是您只能指定一个字符作为分隔符。如果你真的不能使用scanf和company,那么下一站就是手工编写代码(年龄的开头是temp.find_first_of("0123456789");)或使用RE包(TR1如果你的编译器提供它,否则可能Boost)。

答案 2 :(得分:2)

这有什么问题?

std::stringstream convertor("Tom Scott 25");


std::string first, last;
int age;

convertor >> first >> last >> age

如果你真的想一次性阅读,那么这样的事情就可以了

class Name {
  std::string first, last;

 public:

  std::istream& read(std::istream& in) {
    return in >> first >> last;
  }

  operator std::string() const { return first + " " + last; }
};

std::istream& operator>>(std::istream& in, Name& name) {
  return name.read(in);
} 

/* ... */

Name name;
int age;

converter >> name >> age;
std::cout << (std::string)name; 

你想读N个单词的更通用的例子可以这样运作:

class Reader {
int numWords;
std::vector<std::string> words;
// ... 
std::istream& read(std::istream& in) {
  std::vector<std::string> tmp;
  std::string word;
  for (int i = 0; i < numWords; ++i) {
    if (!in >> word)
      return in;
    tmp.push_back(word);
  }

  // don't overwrite current words until success
  words = tmp;
  return in;
}

答案 3 :(得分:2)

您可以实施的常规算法:

read word into name
loop
   try reading integer
   if success then break loop
   else
      clear error flag
      read word and attach to name 

答案 4 :(得分:1)

一种方法是使用重载运算符&gt;&gt;

创建一个新类
class TwoWordString {
public:
    std::string str;
};

istream& operator>>(istream& os; TwoWordString& tws) {
    std::string s1, s2;
    os >> s1;
    os >> s2;
    tws.str = s1 + s2;
    return os;
}

答案 5 :(得分:0)

这是一种矫枉过正的方式(使用Boost.Spirit)&gt;:D

#include <iostream>
#include <string>
#include <boost/format.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>

int main()
{
    namespace qi = boost::spirit::qi;
    namespace phoenix = boost::phoenix;
    namespace ascii = boost::spirit::ascii;
    using ascii::char_; using ascii::digit; using ascii::blank;
    using qi::_1; using qi::int_; using phoenix::ref; using phoenix::at_c;

    std::string input("Sir  Buzz Killington, esq. 25");
    std::string name;
    int age = 0;

    qi::rule<std::string::const_iterator, std::string()> nameRule;
    nameRule %= (+(char_ - digit - blank));

    std::string::const_iterator begin = input.begin();
    std::string::const_iterator end = input.end();
    qi::parse(begin, end,
        (
                nameRule[ref(name) += _1]
            >> *( ((+blank) >> nameRule)[ref(name) += ' ']
                                        [ref(name) += at_c<1>(_1)] )
            >> *blank
            >>  int_[ref(age) = _1]
        )
    );

    std::cout << boost::format("Name: %1%\nAge: %2%\n") % name % age;
    return 0;
}

输出:

  

姓名:Sir Buzz Killington,esq。

     

年龄:25

但是,如果您经常在程序中进行非平凡的输入解析,请考虑使用parsingregular expressions库。

答案 6 :(得分:0)

这是我刚才做的功课。 但是int或double类型必须放在字符串的前面。因此,您可以阅读不同大小的多个单词。 希望这可以帮助你一点点。

string words;
sin>>day>>month>>year;
sin>>words;
watch = words;
while(sin>>words)
{
watch += " "+words;
}

答案 7 :(得分:0)

这是一个std::regex(任意数量的名称)的解决方案:

auto extractNameAndAge(std::string const &s) -> std::tuple<std::string, int> {
  using namespace std::string_literals;

  static auto const r = std::regex{"(.*)\\s+(\\d+)\\s*$"s};

  auto match = std::smatch{};
  auto const matched = std::regex_search(s, match, r);
  if (!matched)
    throw std::invalid_argument{"Invalid input string \""s + s +
                                "\" in extractNameAndAge"s};

  return std::make_tuple(match[1], std::stoi(match[2]));
}

测试:

auto main() -> int {
  using namespace std::string_literals;

  auto lines = std::vector<std::string>{"Jonathan Vincent Voight 76"s,
                                        "Donald McNichol Sutherland 79"s,
                                        "Scarlett Johansson 30"s};

  auto name = ""s;
  auto age = 0;

  for (auto cosnt &line : lines) {
    std::tie(name, age) = extractNameAndAge(line);
    cout << name << " - " << age << endl;
  }
}

输出:

Jonathan Vincent Voight - 76
Donald McNichol Sutherland - 79
Scarlett Johansson - 30