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

convertor >> name >> age;

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

1つの文字列変数に2つ以上の単語を抽出したいのですが。これまで読んだところ、それは不可能のようです。もしそうなら、他にどのようにそれを行うのですか?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

これまでに投稿されたソリューションのほとんどは、実際には仕様を満たしていません。つまり、年齢までのすべてのデータが名前として扱われます。たとえば、「RichardVanDeRothstyne」のような名前で失敗します。

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は区切り文字まで読み取ることができますが、区切り文字として指定できるのは1文字のみです。scanfとcompanyを実際に使用できない場合、次の目的は、手動でコーディングするか(時代の初めはtemp.find_first_of("0123456789");)、REパッケージを使用することです(コンパイラーが提供する場合はTR1、それ以外の場合はおそらくBoost)。

于 2010-01-22T17:37:28.760 に答える
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 に答える
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 に答える
1

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;
}

出力:

名前:サー・バズ・キリントン、esq。

年齢: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 に答える