1

I want to read string and extract all numbers.

Input: 5a3 1f a0aaaa f1fg3

Output: 53 1 0 13

I tried this code:

string s;
getline(cin, s);
stringstream str_strm(s);

int found;
string temp;

while (!str_strm.eof()) {
    str_strm >> temp;
    if (stringstream(temp) >> found)
    {
        cout << found << endl;
    }
}

but when found 5 (from example)after that automatically start to check the other string. How can I extract all numbers?

6 Answers6

1

Please see here the ultra simple example. (There is an even simpler solution at the bottom of this post)

It is using modern C++ elements and algorithms. And has only a few lines of code.

#include <iostream>
#include <string>
#include <regex>
#include <iterator>
#include <algorithm>
#include <sstream>

int main() {

    // Read a string from the console
    if (std::string line{}; std::getline(std::cin, line)) {

        // Put the complete line into a std::istringstream
        std::istringstream iss{line};

        // Print result
        std::transform(std::istream_iterator<std::string>(iss), {}, std::ostream_iterator<std::string>(std::cout, " "),
            [](const std::string& s) { return std::regex_replace(s, std::regex{ R"([^\d])" }, ""); });
    }
    return 0;
}

So, what's going on here. Let us look at it statement by statement. So, first:

if (std::string line{}; std::getline(std::cin, line)) {

This is a if-statement with initializer. If you look up if in the C++ reference, here, then you can see, that we can now have an additional initialization statement as the first part in the if. And why are we using that? Because it is an additional measure for scoping. The variable "line" is only used within the scope of the if statement. It is not needed outside the if. From the functionality point of view, it is the same as writing:

std::string line{};
if (std::getline(std::cin, line)) {

But then, "line" would be also visible outside of the if statement. And, because we want to prevent the pollution of outer namespace, we select this method.

Next is std::getline. This will read a complete line from the input stream, so, from the console (std::cin)and put it into the string. The std::getline returns a reference to the stream. The stream has an overloaded bool operator, that returns, if there was a failure (or end of file) or not. So, the if statement checks, if the input operation works. By the way. All IO-opereations should be checked, if they work or fail.

Good, now we have the complete line of the user input in our variable "line".

With

std::istringstream iss{line};

we put the string into an std::istringstream. We do this, because we want to make use of the C++ "iostream" library. The std::istringstream behaves as any other stream, for example std::cin and you can extract values from it that are separated by a white space. Like in std::cin >> v1 >> v2. The disadvantage for such an approach is, that you need to know the number of values in advance or use a dynamic growing container and a loop.

And this brings ud to our next construct that I want to explain. You may have heard about "iterators". Iterators are like pointers and can point to a range of elements. If you have a std::vector or any other container, then you can iterate with the begin() and end() iterator over all elements in the std::vector without knowing, how many elements are in the std::vector, without knowing how many elements it contains.

And for input streams, we have something similar: The std::istream_iterator. This iterator will iterate over the elements in the std::sitringstream and returns the type of variable given in its template parameter, by repeatedly calling the extractor operator >>. Here, in our case, a std::string. You may know ask: Until when? Where is the end. If you look in the description of the constructor number 1 of the std::istream_operator then you will see, that the default constructor Constructs the end-of-stream iterator. and the default construct can be generated by using the empty braced {} initializer. So {} is the end iterator.

If we want to read all std::strings from the std::istringstream, then we read between std::istream_iterator<std::string>(iss) and {}. So every string that is in the std::istringstream.

Good, next, there is a similar thing for output, the std::ostream_iterator. This will call the inserter operator "<<" for all elements in a given range. And, we can can specify, to which stream it should send the data, here std::cout and additionally a separator-string, which will be appended to the outputted value.

OK, next: std::transform. As it names says, it will transform the elements in a range of elements, between a begin() and end() iterator, to a other range. So, it will transform the elements as shown above from the std::istringstream and send them to the std::ostream iterator. So, we read the source value, transform it, then write it.

But, how to transform. For the transformation, we give a simple lambda function, which calls the std::regex_replace function. This is a standard function, to replace parts of a string with other string data. And, the what that will be replaced is specified by a std::regex. This is a special pattern that is defined in some kind of meta language and matches specified parts of a string. in our case we use [^\d] which means, not a digit. You can test regexes here. You can also lean about them here.

And now, all together, explains the above solution.

All this can be further optimized to 2 statements:

#include <iostream>
#include <string>
#include <regex>

int main() {

    // Read a string from the console
    if (std::string line{}; std::getline(std::cin, line)) {

        // Remove unnecessary characters
        std::cout << std::regex_replace(line, std::regex{ R"([^\d ])" }, "") << "\n";
    }
    return 0;
}

I cannot think of a more simpler solution.

In case of questions, please ask.

Armin Montigny
  • 7,879
  • 3
  • 11
  • 29
1

You could read each space separated word, and then remove the non-digits, like this

std::string word;
while (std::cin >> word)
{
  word.erase(std::remove_if(word.begin(), word.end(), 
               [](unsigned char c) { return not std::isdigit(c); }), 
             word.end());
  std::cout << word << " ";
}

For the input of 5a3 1f a0aaaa f1fg3, it prints 53 1 0 13.

The admittedly odd way of removing elements of a range, is a common idiom.

You could even avoid the loop entirely, if you have the input on a single line

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

word.erase(std::remove_if(word.begin(), word.end(), 
               [](unsigned char c) { return not std::isdigit(c) 
                                        and not std::isspace(c); }), 
           word.end());

std::cout << word;
cigien
  • 50,328
  • 7
  • 37
  • 78
1

Here's a possible solution - while loop is used to separate strings with whitespaces, after that digits are extracted from the sub-strings.

int main()
{
    stringstream ss("5a3 1f a0aaaa f1fg3");
    string str;
    while (getline(ss, str, ' ') ){     
        str.erase(std::remove_if(str.begin(), str.end(), [](unsigned char c) { return !std::isdigit(c); }), str.end());
        cout << str << " ";
    }
}
seccpur
  • 4,680
  • 2
  • 9
  • 17
0

Regular expression pattern matching can be used to find all the digits in the input string.

Here is an example program to find the digits:

// C++ program to find all digits in a string 

#include <bits/stdc++.h> 
using namespace std; 
int main() {
    string inputString;
    cout << "Enter the input string: ";
    getline(cin, inputString);
    cout << "Digits found: ";

    // Define the regular expression matcher and pattern
    smatch matcher; 
    regex pattern("[[:digit:]]");

    while (regex_search(inputString, matcher, pattern)) { 
        // Show the match
        cout << matcher.str(0);

        // Continue searching the rest of the string 
        inputString = matcher.suffix().str(); 
    } 
    return 0; 
} 

Output:

Enter the input string: sdfh354 eutyt;ljkn756897490uiotureu 587689jkgf 90
Digits found: 35475689749058768990

Here is another approach of finding the numbers in the string, without using the regular expression pattern matching:

#include <iostream>
#include <cctype>
#include <bits/stdc++.h> 
using namespace std;

int main() {
    string rawInput;
    cout <<"Enter input string: ";
    getline(cin, rawInput);

    // Get all words from the input string
    stringstream allWords(rawInput);

    // Find and print digits in each word
    string word;
    while(allWords >> word) {
        for(int i = 0; word[i]; i++) {
            // Print only the numbers in the word
            if(isdigit(word[i])) {
                cout<<word[i];
            }
        }
        cout<<" ";
    }
    cout<<"\n";
    return 0;
}

Output:

Enter input string: ghjg45 jsdfj 897897 343yut45 90
45  897897 34345 90 
Gopinath
  • 3,185
  • 1
  • 8
  • 14
  • This does not give the expected output – Armin Montigny Apr 10 '20 at 18:37
  • The program in fact finds all the numbers in a given input string, as per the question. Therefore, it does give the expected output. If the input is 5a3 1f a0aaaa f1fg3, then the output will be 53113. This was the expectation. The program and its output can be verified online at https://www.onlinegdb.com/online_c++_compiler – Gopinath Apr 10 '20 at 18:48
  • In the question above the user specifies the expected output as ````53 1 0 13```` and not ````53113````. The other answers fullfil this requirement. – Armin Montigny Apr 10 '20 at 18:52
  • The requirement is to extract all numbers from a string. The specified program meets the expectation. Formatting can be changed by adding spaces between numbers while printing, or by introducing an extra for loop for each word. – Gopinath Apr 10 '20 at 19:19
  • I now updated the answer with a second approach that does not use regular expressions. – Gopinath Apr 10 '20 at 20:02
0

You can use get from istream to get each character, including whitespace, and then isdigit to check for a digit character...

#include <iostream>
#include <cctype>

int main()
{
    char ch;
    std::cin.get(ch);

    while (!std::cin.eof())
    {
        if (isdigit(ch) || ch == ' ' || ch == '\n')
        {
            std::cout << ch;
        }
        std::cin.get(ch);
    }

    return 0;
}

However, you can avoid using std::cin.eof() for your expression for your While loop as follows...

#include <iostream>
#include <cctype>

int main()
{
    char ch;

    while (std::cin.get(ch))
    {
        if (isdigit(ch) || ch == ' ' || ch == '\n')
        {
            std::cout << ch;
        }
    }

    return 0;
}
Domenic
  • 5,857
  • 2
  • 6
  • 14
0

How can I extract all numbers?

When you KNOW that the input numbers are all hex values ... (and how many)

stringstream ss ("5a3 1f a0aaaa f1fg3"); 
for (int i=0; i<4; ++i)
{
   int k;
   ss >> hex >> k;
   cout << k << endl;
}

with output

1443
31
10529450
3871
2785528
  • 5,162
  • 2
  • 16
  • 18