2009-08-24 87 views
27

我意识到这个问题可能在过去曾多次提出过,但我将继续不管。将包含几个数字的字符串转换为整数

我有一个程序将从键盘输入中获取一串数字。数字将始终以“66 33 9”的形式出现。实质上,每个数字都用空格分隔,用户输入将始终包含不同数量的数字。

我知道,如果每个用户输入的字符串中的数字量是恒定的,那么使用'sscanf'会有效,但对我而言情况并非如此。另外,因为我是C++的新手,我宁愿处理'字符串'变量而不是字符数组。

+6

IMO通常更喜欢'std :: stri ng'原始字符缓冲区不是“新手”的标志,而是成熟度。 – sbi 2009-08-24 09:11:50

回答

29

我假设你想读整行,并解析为输入。因此,首先抢行:

std::string input; 
std::getline(std::cin, input); 

现在把在一个stringstream

std::stringstream stream(input); 

和解析

while(1) { 
    int n; 
    stream >> n; 
    if(!stream) 
     break; 
    std::cout << "Found integer: " << n << "\n"; 
} 

请记住,包括

#include <string> 
#include <sstream> 
+18

你的意思是解析:'int n; while(stream >> n){std :: cout <<“找到整数:”<< n <<“\ n”;}'?更清洁 – 2012-08-28 21:59:10

1

Here is如何将您的字符串拆分为沿着空格的字符串。然后你可以一个接一个地处理它们。

0

尝试strtoken先分开字符串,然后你会处理每个字符串。

2
#include <string> 
#include <vector> 
#include <sstream> 
#include <iostream> 
using namespace std; 

int ReadNumbers(const string & s, vector <int> & v) { 
    istringstream is(s); 
    int n; 
    while(is >> n) { 
     v.push_back(n); 
    } 
    return v.size(); 
} 

int main() { 
    string s; 
    vector <int> v; 
    getline(cin, s); 
    ReadNumbers(s, v); 
    for (int i = 0; i < v.size(); i++) { 
     cout << "number is " << v[i] << endl; 
    } 
} 
8
#include <string> 
#include <vector> 
#include <iterator> 
#include <sstream> 
#include <iostream> 

int main() { 
    std::string input; 
    while (std::getline(std::cin, input)) 
    { 
     std::vector<int> inputs; 
     std::istringstream in(input); 
     std::copy(std::istream_iterator<int>(in), std::istream_iterator<int>(), 
     std::back_inserter(inputs)); 

     // Log process: 
     std::cout << "Read " << inputs.size() << " integers from string '" 
     << input << "'" << std::endl; 
     std::cout << "\tvalues: "; 
     std::copy(inputs.begin(), inputs.end(), 
     std::ostream_iterator<int>(std::cout, " ")); 
     std::cout << std::endl; 
    } 
} 
+3

+1,一旦你用一个“using namespace std;”替换1000“std ::”s并提及你需要的标题。 – 2009-08-24 08:52:29

+5

+1,只要你保留'std ::'前缀。他们的可读性是主观的(我习惯了他们,发现阅读要好得多),但通过完全合格的名称提高清晰度是客观的。 – sbi 2009-08-24 09:14:38

+0

用'使用命名空间'替换后的+1。然后你可以用其他的替换实现,并且不需要应付命名空间的变化。 – nothrow 2009-08-24 09:17:48

1
// get string 
std::string input_str; 
std::getline(std::cin, input_str); 

// convert to a stream 
std::stringstream in(input_str); 

// convert to vector of ints 
std::vector<int> ints; 
copy(std::istream_iterator<int, char>(in), std::istream_iterator<int, char>(), back_inserter(ints)); 
1

无符号值(处理前缀 ' - ' 需要一个额外的布尔)通用的解决方案:

template<typename InIter, typename OutIter> 
void ConvertNumbers(InIter begin, InIter end, OutIter out) 
{ 
    typename OutIter::value_type accum = 0; 
    for(; begin != end; ++begin) 
    { 
     typename InIter::value_type c = *begin; 
     if (c==' ') { 
      *out++ = accum; accum = 0; break; 
     } else if (c>='0' && c <='9') { 
      accum *= 10; accum += c-'0'; 
     } 
    } 
    *out++ = accum; 
     // Dealing with the last number is slightly complicated because it 
     // could be considered wrong for "1 2 " (produces 1 2 0) but that's similar 
     // to "1 2" which produces 1 0 2. For either case, determine if that worries 
     // you. If so: Add an extra bool for state, which is set by the first digit, 
     // reset by space, and tested before doing *out++=accum. 
} 
+0

+1,因为您按照所述的方式回答了问题(“整数”),但我认为这实际上是在某些方面不太通用的方向上的一步,因为它会显然只适用于整数而不适用于其他类型(IOW:“typename OutIter :: value_type accum = 0;”的“通用性”被夸大了)。例如,你将如何处理浮点数?如果你想写另一个迷你词法分析器,不要忘记处理科学记数法和Inf,NaN等。 – 2009-08-24 11:50:28

+0

好吧,它会接受'short []','std :: vector '和'std :: list '或者其他任何整型(包括实现定义的类型)。 Plain 0将转换为所有这些。我在这里使用了valuetype的原因是,当用户传递为__int128 []'和一个数字很大的字符串时,我不会意外地溢出'int'。 – MSalters 2009-08-24 12:47:52

+0

对accum使用value_type绝对是正确的选择,但我想我不明白为什么不能使用istringstream而不是自己的手工制作的词法分析器。然后你可以使用operator <<()(即改进的“typewise”泛型)理解的任何类型,而不会牺牲当前解决方案的“iteratorwise”通用性。我也怀疑这更可能与广泛的字符,区域设置等。 – 2009-08-24 14:42:18

18

C++ String Toolkit Library (Strtk)有以下问题的解决方案:

#include <iostream> 
#include <string> 
#include <deque> 
#include <algorithm> 
#include <iterator> 

#include "strtk.hpp" 

int main() 
{ 
    std::string s = "1 23 456 7890"; 

    std::deque<int> int_list; 
    strtk::parse(s," ",int_list); 

    std::copy(int_list.begin(), 
      int_list.end(), 
      std::ostream_iterator<int>(std::cout,"\t")); 

    return 0; 
} 

更多的例子可以发现Here