質問

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?

役に立ちましたか?

解決

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;
        }
    }
}

他のヒント

atoi can extract numbers from strings even if there are trailing non-digits

int getnum(const char* str)
{
    for(; *str != '\0'; ++str)
    {
        if(*str >= '0' && *str <= '9')
            return atoi(str);
    }
    return YOURFAILURENUMBER;
}

Here's one way

#include <algorithm>
#include <iostream>
#include <locale>
#include <string>

int main(int, char* argv[])
{
  std::string input(argv[1]);

  input.erase(
    std::remove_if(input.begin(), input.end(), 
      [](char c) { return !isdigit(c, std::locale()); }),
    input.end()
  );

  std::cout << std::stoll(input) << '\n';
}

You could also use the <functional> library to create a predicate

auto notdigit = not1(
  std::function<bool(char)>(
    bind(std::isdigit<char>, std::placeholders::_1, std::locale())
  )
);

input.erase(
  std::remove_if(input.begin(), input.end(), notdigit),
  input.end()
);

It's worth pointing out that so far the other two answers hard-code the digit check, using the locale version of isdigit guarantees your program will recognize digits according to the current global locale.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top