Search code examples
c++stringparsingsplitatoi

Extracting integers from strings in C++ with arbitrary structure


This seems like a question that should be easy to search for, but any answers out there seem to be drowned out by a sea of questions asking the more common problem of converting a string to an integer.

My question is: what's an easy way to extract integers from std::strings that might look like "abcd451efg" or "hel.lo42-world!" or "hide num134rs here?" I see that I can use isDigit to manually parse the strings myself, but I'm wondering if there is a more standard way in the vein of atoi or stoi, etc.

The outputs above would be 451, 42, and 134. We can also assume there is only one integer in a string (although a general solution wouldn't hurt). So we don't have to worry about strings like "abc123def456".

Java has an easy solution in the form of

Integer.parseInt(str.replaceAll("[\\D]", ""));

does C++ have something as straightforward?


Solution

  • You can use string::find_first_of("0123456789") to get the position of the first digit, then string::find_last_of("0123456789") to get the position of the last digit, and finally use an atoi on the substring defined by the two positions. I cannot think of anything simpler (without regex).

    BTW, this works only when you have a single number inside the string.

    Here is an example:

    #include <iostream>
    #include <string>
    #include <cstdlib>
    using namespace std;
    
    int main()
    {
        string s = "testing;lasfkj358kdfj-?gt";
        size_t begin = s.find_first_of("0123456789");
        size_t end = s.find_last_of("0123456789");
        string num = s.substr(begin, end - begin + 1);
        int result = atoi(num.c_str());
        cout << result << endl;
    } 
    

    If you have more than 1 number, you can combine string::find_first_of with string::find_first_not_of to get the beginning and the end of each number inside the string.

    This code is the general solution:

    #include <iostream>
    #include <string>
    #include <cstdlib>
    
    using namespace std;
    
    int main()
    {
        string s = "testing;lasfkj358kd46fj-?gt"; // 2 numbers, 358 and 46
    
        size_t begin = 0, end = 0; 
    
        while(end != std::string::npos)
        {
            begin = s.find_first_of("0123456789", end);
            if(begin != std::string::npos) // we found one
            {
                end = s.find_first_not_of("0123456789", begin);
                string num = s.substr(begin, end - begin);
                int number = atoi(num.c_str());
                cout << number << endl;
            }
        }
    }