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

convertor >> name >> age;

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

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

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

例如,我需要的是能够提取之前age的所有单词。

4

8 回答 8

3

这有什么问题?

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

convertor >> firstname >> surname >> age;
std::string name = firstname + " " + surname;
于 2010-01-22T17:26:52.063 回答
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);

不幸的是,iostreams 不提供类似扫描集转换的直接模拟—— getline 最多可以读取一个分隔符,但您只能指定一个字符作为分隔符。如果您真的不能使用 scanf 和 company,那么下一站将是手动编码(时代的开始是temp.find_first_of("0123456789");)或使用 RE 包(如果您的编译器提供它,则为 TR1,否则可能是Boost)。

于 2010-01-22T17:37:28.760 回答
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;
}
于 2010-01-22T17:27:06.063 回答
2

您可以实现的通用算法:

read word into name
loop
   try reading integer
   if success then break loop
   else
      clear error flag
      read word and attach to name 
于 2010-01-22T17:52:40.573 回答
1

一种方法是使用重载运算符创建一个新类>>

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;
}
于 2010-01-22T17:27:03.560 回答
0

这是矫枉过正的方式(使用Boost.Spirit)>: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;
}

输出:

姓名:Buzz Killington 爵士,先生。

年龄:25

说真的,如果您经常在程序中进行重要的输入解析,请考虑使用解析正则表达式库。

于 2010-01-22T21:10:49.683 回答
0

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

string words;
sin>>day>>month>>year;
sin>>words;
watch = words;
while(sin>>words)
{
watch += " "+words;
}
于 2015-06-28T14:51:32.610 回答
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
于 2015-06-28T16:04:18.897 回答