tags:

views:

112

answers:

5

I'd like to test a std::string for containing numbers of any range e.g 5 to 35 in a std::string s = "XDGHYH20YFYFFY" would there be function or I would have to convert a number to string and then use a loop to find each one?

+1  A: 

As much as some people are going to immediately go to regex on this, I think your best bet is actually a hybrid solution. Use REGEX to find numbers, then parse them and see if they're in range.

Something like this in C#. Not sure what regex libraries are available to you in C++.

using System.Text.RegularExpressions.Regex;
using System.Text.RegularExpressions.Match;
using System.Text.RegularExpressions.MatchCollection;

private static const Regex NUMBER_REGEX = new Regex(@"\d+")

public static bool ContainsNumberInRange(string str, int min, int max)
{
    MatchCollection matches = NUMBER_REGEX.Matches(str);
    foreach(Match match in matches)
    {
        int value = Convert.ToInt32(match.Value);
        if (value >= min && value <= max)
            return true;
    }

    return false;
}
jdmichal
You could use boost::regex in C++. I'm not sure about the `\d+` expression; you can be more precise. For instance, the range 3-35 would be found more efficiently with `\d{1,2}` (assuming that X200Y matches)
MSalters
I assumed that X200Y should not match, because that should parse as 200, which is not in range. The problem wasn't specified well enough to know this for sure, though.
jdmichal
+6  A: 

I'd probably use a locale that treated everything except digits as white-space, and read the numbers from a stringstream imbued with that locale and check if they're in range:

#include <iostream>
#include <algorithm>
#include <locale>
#include <vector>
#include <sstream>

struct digits_only: std::ctype<char> 
{
    digits_only(): std::ctype<char>(get_table()) {}

    static std::ctype_base::mask const* get_table()
    {
        static std::vector<std::ctype_base::mask> 
            rc(std::ctype<char>::table_size,std::ctype_base::space);

        std::fill(&rc['0'], &rc['9'], std::ctype_base::digit);
        return &rc[0];
    }
};

bool in_range(int lower, int upper, std::string const &input) { 
    std::istringstream buffer(input);
    buffer.imbue(std::locale(std::locale(), new digits_only()));

    int n;

    while (buffer>>n)
        if (n < lower || upper < n)
            return false;
    return true;
}

int main() {
    std::cout << std::boolalpha << in_range(5, 35, "XDGHYH20YFYFFY");
    return 0;
}
Jerry Coffin
A: 

If you are searching for all of the numbers in the range then use string::find function in a loop. Here is the reference for the function:

http://www.cplusplus.com/reference/string/string/find/

Also do you want to use the numbers in the string only once? For example SDFSD256fdsfs will give you the numbers 2 5 6 25 56 256 if you don't remove them from the string after each match.

Birkan Cilingir
A: 

Are you allowed to have multiple numbers in one string? If so, this solution won't work.

val.erase( remove_if( val.begin(), val.end(), ptr_fun( isalpha ) ) );

which should give you a string containing just the numbers.

wheaties
A: 

You can do this iteratively with a stringstream object.

#include <iostream>
#include <string>
#include <sstream>
#include <cctype>

void check (std::string& s) {
    std::stringstream ss(s);

    std::cout << "Searching string: " << s << std::endl;
    while (ss) {

        while (ss && !isdigit(ss.peek ()))
            ss.get ();

        if (! ss)
            break;

        int i = 0;
        ss >> i;
        std::cout << "  Extraced value: " << i << std::endl;

    }
}


int main () {

    std::string s1 = "XDGHYH20YFYFFY";
    std::string s2 = "20YF35YFFY100";
    check (s1);
    check (s2);
    return 0;
}

Yields:

Searching string: XDGHYH20YFYFFY
  Extraced value: 20
Searching string: 20YF35YFFY100
  Extraced value: 20
  Extraced value: 35
  Extraced value: 100

Adding parameters to the check function to limit the results accepted would be trivial.

ezpz