В IOStreams строки (имеются в виду как C-строки, так и строки C++) практически не требуют форматирования. Любые и все символы извлекаются в строку только до тех пор, пока не будет найден пробельный символ или пока не будет перехвачен конец потока. В вашем примере вы используете строку, предназначенную для заполнения запятых между важными данными, но результат, который вы испытываете, является результатом поведения, которое я только что объяснил: строка dummy
не просто поглощает запятую, но также остальная часть последовательности символов до следующего символа пробела.
Чтобы избежать этого, вы можете использовать char
для фиктивной переменной, в которой есть место только для одного символа. И если вы хотите поместить Apple 1
в строку, вам понадобится неформатированное извлечение, потому что форматированное извлечение operator>>()
читает только до пробела. Подходящей функцией для использования здесь является std::getline()
:
string c;
char dummy;
if ((stream >> a >> dummy >> b >> dummy) &&
std::getline(stream >> std::ws, s))
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
{
}
Очистка новой строки после форматированного извлечения также необходима, поэтому я использовал std::ws
для очистки начального пробела. Я также использую оператор if
для содержания извлечения, чтобы определить, удалось оно или нет.
Любой более плавный способ сделать это очень помог бы мне.
Вы можете установить классификацию символа запятой как символ пробела, используя фасет std::ctype<char>
языкового стандарта, встроенного в поток. Это сделает ненужным использование фиктивной переменной. Вот пример:
namespace detail
{
enum options { add, remove };
class ctype : public std::ctype<char>
{
private:
static mask* get_table(const std::string& ws, options opt)
{
static std::vector<mask> table(classic_table(),
classic_table() + table_size);
for (char c : ws)
{
if (opt == add)
table[c] |= space;
else if (opt == remove)
table[c] &= ~space;
}
return &table[0];
}
public:
ctype(const std::string& ws, options opt)
: std::ctype<char>(get_table(ws, opt)) { }
};
}
class adjustws_impl
{
public:
adjustws_impl(const std::string& ws, detail::options opt) :
m_ws(ws),
m_opt(opt)
{ }
friend std::istream& operator>>(std::istream& is,
const adjustws_impl& manip)
{
const detail::ctype* facet(new detail::ctype(manip.m_ws, manip.m_opt));
if (!std::has_facet<detail::ctype>(is.getloc())
{
is.imbue(std::locale(is.getloc(), facet));
} else
delete facet;
return is;
}
private:
std::string m_ws;
detail::options m_opt;
};
adjustws_impl setws(const std::string& ws)
{
return adjustws_impl(ws, detail::add);
}
adjustws_impl unsetws(const std::string& ws)
{
return adjustws_impl(ws, detail::remove);
}
int main()
{
std::istringstream iss("10,1.546,Apple 1");
int a; double b; std::string c;
iss >> setws(","); // set comma to a whitespace character
if ((iss >> a >> b) && std::getline(iss >> std::ws, c))
{
// ...
}
iss >> unsetws(","); // remove the whitespace classification
}
person
0x499602D2
schedule
16.02.2014
string dummy;
д'ой. Я смотрел на код как идиот и не видел его :) - person jrok   schedule 16.02.2014Apple 1
, и я ничего не получаю, теперь я получаюApple
, но все еще неApple 1
. Любые идеи? - person Sunil Kundal   schedule 16.02.2014Apple
и1
. Вам нужно использоватьstd::getline()
(конечно, после очистки новой строки). - person 0x499602D2   schedule 16.02.2014