5

I know how to convert a complete string into integer(using std::stoi). But can you guide me how to extract integer from a string. For example, I want to extract the integer 15 from string a15a.

string x="a15a";
int a = std::stoi(x);

This above method works fine if the integer is at the start of the string. For example, If the value of string x is "15a", it converts it into integer the 15. But it does not work if integer is present somewhere in the middle of the string. How to extract an integer from in between the string. Thanks.

mango
  • 165
  • 9
  • 3
    First use [substr](https://en.cppreference.com/w/cpp/string/basic_string/substr) to extract the numeric part to use with `stoi`. – acraig5075 Nov 13 '19 at 08:42
  • 2
    Can you give us more details about your input? Is it of a fixed format (i.e. letter, then the number, then possibly other letters)? Do you always have just one part with digits? (i.e. not "a15a21b")? – bznein Nov 13 '19 at 08:43
  • Yes my input is a fixed format like this: `"15a16a17"`. I want to extract `15`, `16`, and `17` from it. It has three integers in it. – mango Nov 13 '19 at 08:47
  • @UsamaTahir is the separator always `a` - and always a single character? – Wolf Nov 13 '19 at 08:48
  • @acraig5075 I like your idea of `substr`. May be I can extract three substrings from my input and store them in integers. For example in `"15a16a17"`, I can use `substr(0,1)`, `substr(3,4)` and `substr(6,7)`. – mango Nov 13 '19 at 08:51
  • First use `std::remove_if` to remove all the letters, then convert the resulting string to integer with `std::atoi` – Alejandro Blasco Nov 13 '19 at 08:52
  • yes @Wolf `a` is always a single character. – mango Nov 13 '19 at 08:52
  • 1
    @UsamaTahir then you can [split by this char](https://stackoverflow.com/a/10058725/2932052) – Wolf Nov 13 '19 at 08:54
  • Do you want to handle the negative numbers as well? – Iman Kianrostami Nov 13 '19 at 09:35

6 Answers6

6

With C++17 you can use std::from_chars to extract a numeric value from a sequence of characters. You code would look something like:

std::string x = "a15a";
int a = 0; // initialize with some value in case parsing fails
std::from_chars(&x[1], &x[3], a); // parse from [first, last) range of chars

Note that I've omitted error checking. Read that link to see how to use the return value from the function.

Blastfurnace
  • 18,411
  • 56
  • 55
  • 70
2

Another way: You could replace non-digits with spaces so as to use stringstring extraction of the remaining integers directly:

std::string x = "15a16a17";
for (char &c : x)
{
    if (!isdigit(c))
        c = ' ';
}

int v;
std::stringstream ss(x);
while (ss >> v)
    std::cout << v << "\n";

Output:

15
16
17
acraig5075
  • 10,588
  • 3
  • 31
  • 50
  • Wouldn't this make negative numbers appear positive? – Toby Speight Nov 13 '19 at 09:24
  • @TobySpeight Yes it would, just like it wouldn't accommodate decimal values either. But then the question doesn't imply that those are considerations. – acraig5075 Nov 13 '19 at 09:27
  • I think the question does imply that numbers can be negative (though not fractional), through the use of signed `int` for the result. If only positive values were useful, that would be an unsigned type, surely? – Toby Speight Nov 13 '19 at 09:29
1

You can check each character using isdigit() function to determine if it is a digit or not. Then you can combine sequential digits to extract the integer. This way you can extract numbers from any string not just separated by on specific char.

Update:

As mentioned by @Toby I updated the code to handle negative numbers as well.

string input="14aaa15d-16fff-fff17";
string tmp = "";
vector<int> output;
for (int i = 0; i < input.size(); ++i)
{
    if (isdigit(input[i]))
    {
        if(i>0 && input[i-1]=='-')
            tmp+='-';
        tmp+=input[i];
    }
    else if(tmp.size()>0)
    {
        output.push_back(stoi(tmp));
        tmp = "";
    }
}

if (tmp.size()>0)
    output.push_back(stoi(tmp));

for (int i = 0; i < output.size(); ++i)
    printf("%d ", output[i]);

Output:

14
15
-16
17
Iman Kianrostami
  • 482
  • 3
  • 13
  • @TobySpeight It works only for positive numbers (like other answers so far) but you can edit the code to handle negative numbers as well – Iman Kianrostami Nov 13 '19 at 09:26
0

If it's always the single character a that separates decimal numbers, the task changes into "Splitting a string by a character". Here is my adaption of the accepted answer to the same-name SO question:

std::stringstream input("15a16a17");
std::string part;
std::vector<int> numbers;

while(std::getline(input, part, 'a'))
{
   numbers.push_back(std::stoi(part));
}
Wolf
  • 9,679
  • 7
  • 62
  • 108
0

You can do it quite simply by using a function to location the first occurrence of a digit in your string. Including <cstring> makes strspn() available and makes the process trivial.

For example to find the first digit character in "a15a" you can simply make the call:

    int a;
    size_t off, pos;
    std::string x = "a15a";

    off = strcspn (x.c_str(), "0123456789");    /* get no. chars to 1st digit */

off now holds the offset to the first digit in x. The conversion at that point is simple, but to validate the conversion you must use the try {...} catch (exception) {...} format or you will not know whether the value a after the attempted conversion is valid or not, e.g.

    try {   /* validate using try {..} catch (exception) {..} */
        a = std::stoi(x.c_str() + off, &pos);   /* good conversions, store a */
        std::cout << a << '\n';                 /* output number in "a15a" */
    }
    catch (const std::exception & e) {
        std::cerr << e.what() << '\n';
        return 1;
    }

That's all that is required to locate the start of the digits in x and then to validate the conversion at x + off to arrive at the desired integer value.

Putting it altogether, you would have:

#include <iostream>
#include <string>
#include <cstring>

int main() {

    int a;
    size_t off, pos;
    std::string x = "a15a";

    off = strcspn (x.c_str(), "0123456789");    /* get no. chars to 1st digit */
    try {   /* validate using try {..} catch (exception) {..} */
        a = std::stoi(x.c_str() + off, &pos);   /* good conversions, store a */
        std::cout << a << '\n';                 /* output number in "a15a" */
    }
    catch (const std::exception & e) {
        std::cerr << e.what() << '\n';
        return 1;
    }
}

Example Use/Output

$ /bin/stoi_int
15
David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
0

Regex way :

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

int main()
{
 using namespace std;

std::string subject("a1b2c12d1212e");
try {
  std::regex re("\\d+");
  std::sregex_iterator next(subject.begin(), subject.end(), re);
  std::sregex_iterator end;
  while (next != end) {
    std::smatch match = *next;
    std::cout << "number " << match.str() << "\n";
    next++;
  } 
} catch (std::regex_error& e) {
  // Syntax error in the regular expression
}

 return EXIT_SUCCESS;
}
Agnius Vasiliauskas
  • 10,935
  • 5
  • 50
  • 70