C++ 使用stringstream从混合字符串中提取数字

C++ 使用stringstream从混合字符串中提取数字,c++,C++,我正在尝试使用stringstream从字符串中提取数字,如Hello1234。我已经编写了一段代码,用于在输入时从字符串中提取数字,如: 你好1234世界9876你好1234 将12349876作为输出 但它不会读取同时包含字符串和数字的混合字符串。我们如何提取它? -例如:Hello1234应该给出1234 以下是我到目前为止的代码: cout << "Welcome to the string stream program. " << endl; strin

我正在尝试使用stringstream从字符串中提取数字,如Hello1234。我已经编写了一段代码,用于在输入时从字符串中提取数字,如:

你好1234世界9876你好1234

12349876作为输出 但它不会读取同时包含字符串和数字的混合字符串。我们如何提取它? -例如:Hello1234应该给出1234

以下是我到目前为止的代码:

cout << "Welcome to the string stream program. " << endl;
    string string1;
    cout << "Enter a string with numbers and words: ";
    getline(cin, string1);

    stringstream ss; //intiazling string stream

    ss << string1;  //stores the string in stringstream 

    string temp;  //string for reading words
    int number;   //int for reading integers

    while(!ss.eof()) {
        ss >> temp;
        if (stringstream(temp) >> number) {
            cout << "A number found is: " << number << endl;
        }
    }
cout编号){

cout如果您不局限于使用
std::stringstream
的解决方案,我建议您看看。示例:

int main() {
    std::string s = "Hello 123 World 456 Hello789";    
    std::regex regex(R"(\d+)");   // matches a sequence of digits

    std::smatch match;
    while (std::regex_search(s, match, regex)) {
        std::cout << std::stoi(match.str()) << std::endl;
        s = match.suffix();
    }
}
在进行流提取之前,只需将字符串中的任何字符替换为空白即可

std::string str = "Hello 1234 World 9876 Hello1234";

for (char& c : str)
{
    if (isalpha(c))
        c = ' ';
}

std::stringstream ss(str);

int val;
while (ss >> val)
    std::cout << val << "\n";

您可以将下面的代码与任何类型的流一起使用—
stringstream
。它从流读取到第一个数字。数字放回流中,然后像通常一样读取数字

添加我的版本:

#包括
#包括
#包括
int main(){
std::字符串s;
标准::getline(标准::cin,s);
std::stringstream-ss;
整数;
用于(常量字符c:s){
if(std::isdigit(static_cast(c)){//多亏了Aconcagua
ss>数量){
std::cout编号)
{

std::cout问题本身非常琐碎,作为程序员,我们大多数人每天都在解决这类问题。我们知道,对于任何给定的问题,都有很多解决方案,但作为程序员,我们试图找出任何给定问题的最佳解决方案

当我遇到这个问题时,已经有很多有用且正确的答案,但为了满足我的好奇心,我尝试对所有其他解决方案进行基准测试,以找出最佳的解决方案

我找到了上面最好的一个,觉得还有一些改进的空间

所以我在这里发布了我的解决方案和基准代码

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

using namespace std;
#define REQUIER_EQUAL(x, y)                                                    \
  if ((x) != (y)) {                                                            \
    std::cout << __PRETTY_FUNCTION__ << " failed at :" << __LINE__             \
              << std::endl                                                     \
              << "\tx:" << (x) << "\ty:" << (y) << std::endl;                  \
    ;                                                                          \
  }
#define RUN_FUNCTION(func, in, out)                                            \
  auto start = std::chrono::system_clock::now();                               \
  func(in, out);                                                               \
  auto stop = std::chrono::system_clock::now();                                \
  std::cout << "Time in " << __PRETTY_FUNCTION__ << ":"                        \
            << std::chrono::duration_cast<std::chrono::microseconds>(stop -    \
                                                                     start)    \
                   .count()                                                    \
            << " usec" << std::endl;

//Solution by @Evg 
void getNumbers1(std::string input, std::vector<int> &output) {
  std::regex regex(R"(\d+)"); // matches a sequence of digits
  std::smatch match;
  while (std::regex_search(input, match, regex)) {
    output.push_back(std::stoi(match.str()));
    input = match.suffix();
  }
}
//Solution by @n314159 
void getNumbers2(std::string input, std::vector<int> &output) {
  std::stringstream ss;
  int number;
  for (const char c : input) {
    if (std::isdigit(static_cast<unsigned char>(c))) { // Thanks to Aconcagua
      ss << c;
    } else if (ss >> number) {
      output.push_back(number);
    }
  }
}

//Solution by @The Failure by Design 
void getNumbers3(std::string input, std::vector<int> &output) {
  istringstream is{input};
  char c;
  int n;
  while (is.get(c)) {
    if (!isdigit(static_cast<unsigned char>(c)))
      continue;
    is.putback(c);
    is >> n;
    output.push_back(n);
  }
}
//Solution by @acraig5075 
void getNumbers4(std::string input, std::vector<int> &output) {
  for (char &c : input) {
    if (isalpha(c))
      c = ' ';
  }
  std::stringstream ss(input);
  int val;
  while (ss >> val)
    output.push_back(val);
}
//Solution by me 
void getNumbers5(std::string input, std::vector<int> &output) {
  std::size_t start = std::string::npos, stop = std::string::npos;
  for (auto i = 0; i < input.size(); ++i) {
    if (isdigit(input.at(i))) {
      if (start == std::string::npos) {
        start = i;
      }
    } else {
      if (start != std::string::npos) {
        output.push_back(std::stoi(input.substr(start, i - start)));
        start = std::string::npos;
      }
    }
  }
  if (start != std::string::npos)
    output.push_back(std::stoi(input.substr(start, input.size() - start)));
}

void test1_getNumbers1() {
  std::string input = "Hello 123 World 456 Hello789 ";
  std::vector<int> output;
  RUN_FUNCTION(getNumbers1, input, output);
  REQUIER_EQUAL(output.size(), 3);
  REQUIER_EQUAL(output[0], 123);
  REQUIER_EQUAL(output[1], 456);
  REQUIER_EQUAL(output[2], 789);
}
void test1_getNumbers2() {
  std::string input = "Hello 123 World 456 Hello789";
  std::vector<int> output;
  RUN_FUNCTION(getNumbers2, input, output);
  REQUIER_EQUAL(output.size(), 3);
  REQUIER_EQUAL(output[0], 123);
  REQUIER_EQUAL(output[1], 456);
  REQUIER_EQUAL(output[2], 789);
}
void test1_getNumbers3() {
  std::string input = "Hello 123 World 456 Hello789";
  std::vector<int> output;
  RUN_FUNCTION(getNumbers3, input, output);
  REQUIER_EQUAL(output.size(), 3);
  REQUIER_EQUAL(output[0], 123);
  REQUIER_EQUAL(output[1], 456);
  REQUIER_EQUAL(output[2], 789);
}

void test1_getNumbers4() {
  std::string input = "Hello 123 World 456 Hello789";
  std::vector<int> output;
  RUN_FUNCTION(getNumbers4, input, output);
  REQUIER_EQUAL(output.size(), 3);
  REQUIER_EQUAL(output[0], 123);
  REQUIER_EQUAL(output[1], 456);
  REQUIER_EQUAL(output[2], 789);
}
void test1_getNumbers5() {
  std::string input = "Hello 123 World 456 Hello789";
  std::vector<int> output;
  RUN_FUNCTION(getNumbers5, input, output);
  REQUIER_EQUAL(output.size(), 3);
  REQUIER_EQUAL(output[0], 123);
  REQUIER_EQUAL(output[1], 456);
  REQUIER_EQUAL(output[2], 789);
}

int main() {
  test1_getNumbers1();
  // test1_getNumbers2();
  test1_getNumbers3();
  test1_getNumbers4();
  test1_getNumbers5();
  return 0;
}


如果您想使用stringstream,可以迭代
string1
,将每个数字或空格字符添加到
ss
,然后提取数字。使用
get
逐个获取字符。读取数字后,使用
putback
将其放回流中,然后像读取数字一样读取数字RMALY do:
ss>>n
@ZDF
peek
+
ignore
可能是更好的选择…@Aconcagua我认为它是等效的,只是更多的行。@ZDF因为我们需要一个else分支?也许……我个人更喜欢在需要之前不修改对象。不过,在我看来,从流中提取一个字符,然后将其放回是等效的如果不需要的话,可以将一个对象推到一个向量中,然后再次移除,而偷看则对应于第一次检查,如果需要的话,只推一次。承认,流上的开销要少得多…对于
“Hello1234World9876Hello1234”来说,这不会失败吗
?@Evg是的。也许OP可以用更多的例子来阐明要求。也许只是不删除,而是替换为空格?为了完全安全,应该将
isalpha
的参数转换为unsigend(请参阅)。为了完全安全,
isdigit
需要将字符转换为unsigned(请参阅)@Aconcagua我错过了这一条-谢谢。对目前的情况来说可能不重要。同意,但最好从一开始就习惯,否则人们可能会忘记什么时候需要,然后被咬;)@Aconcagua改变了。:o)刚刚发现:“[…]只有更多的行”–实际上更少:
while((c=is.peek())!=std::istream::traits_type::eof(){if(isdigit)return是>>n;is.ignore();}
–但是while条件很难看;)为了完全安全,
isdigit
需要将字符转换为无符号字符(请参见)。@n314159是否运行过此代码?我尝试了
gcc(Ubuntu 7.4.0-1ubuntu1~18.04.1)7.4.0
没有给出任何输出。我确实给出了。但是再看一遍,如果字符串以最后一个数字结尾,似乎不会输出最后一个数字。我将稍后再试。@ManthanTilva修复了它。这不是一个有效的测试。更改测试调用的顺序,您将得到不同的结果。这是我得到的:
测试1中的时间\u getNumbers5:7 usec测试中的时间1\u GetNumbers 1:62 usec测试中的时间1\u GetNumbers 4:21 usec测试中的时间3:4 usec
加上:您的代码没有
-请参阅问题标题。OP不是要求快速解决方案,而是要求解决方案。@TheFailurebyDesign,只是通过重新排序进行检查。您是对的。知道原因吗?如何克服此问题?缓存,可能请尝试分别运行每个测试。
#include <iostream>

using namespace std;

istream& get_number( istream& is, int& n )
{
  while ( is && !isdigit( static_cast<unsigned char>( is.get() ) ) )
    ;
  is.unget();
  return is >> n;
}

int main()
{
  int n;
  while ( get_number( cin, n ) )
    cout << n << ' ';
}
const char* get_number( const char*& s, int& n )
{
  // end of string
  if ( !*s )
    return 0;

  // skip to first digit
  while ( !isdigit( static_cast<unsigned char>( *s ) ) )
    ++s;

  // convert
  char* e;
  n = strtol( s, &e, 10 );
  return s = e;
}
//...
while ( get_number( s, n ) )
//...
#include <chrono>
#include <iostream>
#include <regex>
#include <sstream>
#include <string>
#include <vector>

using namespace std;
#define REQUIER_EQUAL(x, y)                                                    \
  if ((x) != (y)) {                                                            \
    std::cout << __PRETTY_FUNCTION__ << " failed at :" << __LINE__             \
              << std::endl                                                     \
              << "\tx:" << (x) << "\ty:" << (y) << std::endl;                  \
    ;                                                                          \
  }
#define RUN_FUNCTION(func, in, out)                                            \
  auto start = std::chrono::system_clock::now();                               \
  func(in, out);                                                               \
  auto stop = std::chrono::system_clock::now();                                \
  std::cout << "Time in " << __PRETTY_FUNCTION__ << ":"                        \
            << std::chrono::duration_cast<std::chrono::microseconds>(stop -    \
                                                                     start)    \
                   .count()                                                    \
            << " usec" << std::endl;

//Solution by @Evg 
void getNumbers1(std::string input, std::vector<int> &output) {
  std::regex regex(R"(\d+)"); // matches a sequence of digits
  std::smatch match;
  while (std::regex_search(input, match, regex)) {
    output.push_back(std::stoi(match.str()));
    input = match.suffix();
  }
}
//Solution by @n314159 
void getNumbers2(std::string input, std::vector<int> &output) {
  std::stringstream ss;
  int number;
  for (const char c : input) {
    if (std::isdigit(static_cast<unsigned char>(c))) { // Thanks to Aconcagua
      ss << c;
    } else if (ss >> number) {
      output.push_back(number);
    }
  }
}

//Solution by @The Failure by Design 
void getNumbers3(std::string input, std::vector<int> &output) {
  istringstream is{input};
  char c;
  int n;
  while (is.get(c)) {
    if (!isdigit(static_cast<unsigned char>(c)))
      continue;
    is.putback(c);
    is >> n;
    output.push_back(n);
  }
}
//Solution by @acraig5075 
void getNumbers4(std::string input, std::vector<int> &output) {
  for (char &c : input) {
    if (isalpha(c))
      c = ' ';
  }
  std::stringstream ss(input);
  int val;
  while (ss >> val)
    output.push_back(val);
}
//Solution by me 
void getNumbers5(std::string input, std::vector<int> &output) {
  std::size_t start = std::string::npos, stop = std::string::npos;
  for (auto i = 0; i < input.size(); ++i) {
    if (isdigit(input.at(i))) {
      if (start == std::string::npos) {
        start = i;
      }
    } else {
      if (start != std::string::npos) {
        output.push_back(std::stoi(input.substr(start, i - start)));
        start = std::string::npos;
      }
    }
  }
  if (start != std::string::npos)
    output.push_back(std::stoi(input.substr(start, input.size() - start)));
}

void test1_getNumbers1() {
  std::string input = "Hello 123 World 456 Hello789 ";
  std::vector<int> output;
  RUN_FUNCTION(getNumbers1, input, output);
  REQUIER_EQUAL(output.size(), 3);
  REQUIER_EQUAL(output[0], 123);
  REQUIER_EQUAL(output[1], 456);
  REQUIER_EQUAL(output[2], 789);
}
void test1_getNumbers2() {
  std::string input = "Hello 123 World 456 Hello789";
  std::vector<int> output;
  RUN_FUNCTION(getNumbers2, input, output);
  REQUIER_EQUAL(output.size(), 3);
  REQUIER_EQUAL(output[0], 123);
  REQUIER_EQUAL(output[1], 456);
  REQUIER_EQUAL(output[2], 789);
}
void test1_getNumbers3() {
  std::string input = "Hello 123 World 456 Hello789";
  std::vector<int> output;
  RUN_FUNCTION(getNumbers3, input, output);
  REQUIER_EQUAL(output.size(), 3);
  REQUIER_EQUAL(output[0], 123);
  REQUIER_EQUAL(output[1], 456);
  REQUIER_EQUAL(output[2], 789);
}

void test1_getNumbers4() {
  std::string input = "Hello 123 World 456 Hello789";
  std::vector<int> output;
  RUN_FUNCTION(getNumbers4, input, output);
  REQUIER_EQUAL(output.size(), 3);
  REQUIER_EQUAL(output[0], 123);
  REQUIER_EQUAL(output[1], 456);
  REQUIER_EQUAL(output[2], 789);
}
void test1_getNumbers5() {
  std::string input = "Hello 123 World 456 Hello789";
  std::vector<int> output;
  RUN_FUNCTION(getNumbers5, input, output);
  REQUIER_EQUAL(output.size(), 3);
  REQUIER_EQUAL(output[0], 123);
  REQUIER_EQUAL(output[1], 456);
  REQUIER_EQUAL(output[2], 789);
}

int main() {
  test1_getNumbers1();
  // test1_getNumbers2();
  test1_getNumbers3();
  test1_getNumbers4();
  test1_getNumbers5();
  return 0;
}
Time in void test1_getNumbers1():703 usec
Time in void test1_getNumbers3():17 usec
Time in void test1_getNumbers4():10 usec
Time in void test1_getNumbers5():6 usec