Построить stringstream из char

Я реализовал следующий код, который делает то, что должен, но я думаю, что его можно/нужно упростить.

По сути, мне нужно создать вектор чисел, каждое из которых содержит одну из цифр, найденных в testString. Есть ли способ построить поток строк непосредственно из символа (т.е. testString [i])? Я бы предпочел не использовать функции в стиле C, такие как atoi, если это можно сделать на языке C++.

#include <iostream>
#include <string>
#include <sstream>
#include <vector>

int main ()
{
    std::string testString = "abc123.bla";
    std::string prefix = "abc";

    std::vector<unsigned short> digits;

    if (0 == testString.find(prefix))
    {
        for (size_t i = prefix.size(); i < testString.find("."); ++i)
        {
            int digit;
            std::stringstream digitStream;
            digitStream << testString[i];
            digitStream >> digit;
            digits.emplace_back(digit);
        }
    }

    for (std::vector<unsigned short>::iterator digit = digits.begin(); digit < digits.end(); ++digit)
    {
        std::cout << *digit << std::endl;
    }

    return 0;
}

person Mihai Todor    schedule 11.09.2012    source источник
comment
Вы можете использовать конструктор строк, который принимает символ и номер этого символа для его построения (например, (3, 'a') == aaa).   -  person chris    schedule 11.09.2012
comment
testString[i] - '0' если я правильно понял.   -  person obataku    schedule 11.09.2012
comment
@oldrinb testString[i] будет оцениваться как «1», «2», «3» во время итераций.   -  person Mihai Todor    schedule 11.09.2012
comment
@MihaiTodor '1' - '0' оценивается как 1, '2' - '0' как 2 и т. д.   -  person obataku    schedule 11.09.2012
comment
@oldrinb Да, теперь я это вижу. Спасибо!   -  person Mihai Todor    schedule 11.09.2012
comment
Осторожно, он работает только с цифрами, а не с буквами.   -  person chris    schedule 11.09.2012
comment
@chris Вы имеете в виду проблемы ASCII и UTF8?   -  person Mihai Todor    schedule 11.09.2012
comment
@MihaiTodor, использование ASCII не гарантируется. Просто посмотрите на что-то вроде таблицы кодов символов EBCDIC.   -  person chris    schedule 11.09.2012
comment
@chris Да, ну, будем надеяться, что мне не нужно будет открывать банку с червями :D   -  person Mihai Todor    schedule 12.09.2012


Ответы (2)


Предполагая, что testString[i] находится между '0' и '9', просто выполните:

digits.emplace_back(testString[i] - '0');
person jrok    schedule 11.09.2012
comment
Оооо... Хорошая идея! Почему я этого не видел? Спасибо! :) - person Mihai Todor; 11.09.2012
comment
@jrok, этому строковому конструктору нет равных. Технически вы можете попробовать что-то вроде std::string num(123);, и он создаст его с любым символом 123 вместо длины 123 или строкового представления 123. - person chris; 11.09.2012
comment
@chris Ты прав, спасибо. Я просто предположил, что это будет так, мне никогда раньше не приходилось создавать строку из 1 символа :) Это работает: std::istringstream digitStream(std::string(1, testString[i])); - person jrok; 11.09.2012
comment
@jork: Да, мне это тоже удалось, но ваше решение намного элегантнее. Спасибо еще раз! - person Mihai Todor; 11.09.2012

См. мой оригинальный комментарий; вычтите '0' из каждого символа цифры.

#include <string>
#include <vector>
#include <algorithm>
#include <iterator>
#include <cctype>
#include <functional>
#include <iostream>

...

std::string input = "abc123.bla";
std::string prefix = "abc";
std::vector<unsigned short> digits;

auto input_b = input.begin();
std::copy_if(input_b, std::find(input_b, input.end(), '.'),
    std::back_inserter(digits), (int (*)(int)) std::isdigit);

auto digits_b = digits.begin();
auto digits_e = digits.end();
std::transform(digits_b, digits_e, digits_b,
    std::bind2nd(std::minus<unsigned short>(), '0'));
std::copy(digits_b, digits_e,
    std::ostream_iterator<unsigned short>(std::cout, "\n"));

Его можно даже сократить, если вам не нужно, чтобы digits содержало промежуточные значения цифр.

std::transform(digits.begin(), digits.end(),
    std::ostream_iterator<unsigned short>(std::cout, "\n"),
    std::bind2nd(std::minus<unsigned short>(), '0'));
person obataku    schedule 11.09.2012
comment
Спасибо, что нашли время, чтобы предоставить такой подробный подход, но я боюсь, что моих знаний о STL недостаточно, чтобы понять, что там происходит. Я рассмотрю std::copy_if, std::back_inserter, std::transform, std::bind2nd и std::minus, так как никогда раньше ими не пользовался. - person Mihai Todor; 12.09.2012