tags:

views:

363

answers:

5

I have a long string, and I'd like to loop through it and pull out all the int values in order. This seems simple enough, but I can't seem to figure it out.

string raw = "I am a string and I have some numbers 3 45 333 2 39 inside of me 1839 9303, and I'd like to get these numbers into 9 -10 00  9e09 into a string[] or something else";

int[] justNumbers = raw.?????

Using C# .NET 3.5 and have access to Regex and Linq if necessary. Thanks.

Final result would be a long list of ints. i.e.

List<int> numbers = new List<int>();

WHAT I ENDED UP USING (NOT THE MOST EFFICIENT, BUT WORKED)

#region mysolution
        numbers = new List<int>();
        foreach (char item in raw)
        {
            if (item.ToString() == "0")
            {
                numbers.Add(Convert.ToInt32(item.ToString()));
            }
            else if (item.ToString() == "1")
            {
                numbers.Add(Convert.ToInt32(item.ToString()));
            }
            else if (item.ToString() == "2")
            {
                numbers.Add(Convert.ToInt32(item.ToString()));
            }
            else if (item.ToString() == "3")
            {
                numbers.Add(Convert.ToInt32(item.ToString()));
            }
            else if (item.ToString() == "4")
            {
                numbers.Add(Convert.ToInt32(item.ToString()));
            }
            else if (item.ToString() == "5")
            {
                numbers.Add(Convert.ToInt32(item.ToString()));
            }
            else if (item.ToString() == "6")
            {
                numbers.Add(Convert.ToInt32(item.ToString()));
            }
            else if (item.ToString() == "7")
            {
                numbers.Add(Convert.ToInt32(item.ToString()));
            }
            else if (item.ToString() == "8")
            {
                numbers.Add(Convert.ToInt32(item.ToString()));
            }
            else if (item.ToString() == "9")
            {
                numbers.Add(Convert.ToInt32(item.ToString()));
            }
        }

        #endregion
+7  A: 

Something along the lines of: (untested)

var items = raw.Split(' ');
var integers = new List<int>();
foreach(var i in items){
    int test = 0;
    if(int.TryParse(i, out test)){
        integers.add(test);
    }
}

EDIT: There is an overload of TryParse that takes as a parameter, among other things, a bitwise comparison of System.Globalization.NumberStyles. With this overload, you can specify what types of integer strings it can accept (AllowExponent is one of them), so I would imagine, having not tested this that 9e09 would work. :)

Hope this helps!

Pwninstein
This doesn't seem to work on 9e09 either :(
Bryan
this worked well for my simple issue. I also just did a series of if/else statements comparing i.ToString == "0" for each number 0-9
discorax
@discorax ?? what code did you add? Please update your question with what you went with--your comment makes me very curious
Michael Haren
+6  A: 

A regex-based approach would look something like this:

Regex number = new Regex(@"-?\d+");
List<int> ints = number.Matches(raw)
                       .Cast<Match>()
                       .Select(m => Int32.Parse(m.Value))
                       .ToList();

However, this doesn't handle 9e09 if that's meant to represent 9 x 10 ^ 9 -- it will interpret it as two separate numbers, parsed as 9 and 9.

itowlson
I applaud your line count but...that is a crazy application of sophisticated tech for this simple problem
Michael Haren
The e case could be handle by changing it to \de?\d* .Not sure which isymbol to use for the conditional e since I'm used to Perl RegExp but the ? in phrase mean 0 or 1
David Brunelle
@Michael : Got something better to suggest?
David Brunelle
Looks clean. What happens if Int32.Parse() throws an exception?
Cory Charlton
@David Brunelle: This one looks pretty nice: http://stackoverflow.com/questions/2240488/2240514#2240514
Michael Haren
Michael: could you say a bit more? Is it the use of regexes or the use of LINQ that you feel is a bad choice? I'm sympathetic to the regex criticism but on the other hand picking out recognisable patterns like digit sequences seems to me like a canonical use of the tool... always willing to learn though! Thanks!
itowlson
@Michael: I think regex is a perfect solution here. Any time you need to do command or parameter parsing it really comes in handy. Sites like regexr.com are really great when used in parallel -- they make it super simple to test out your regex and visually identify all of the matching groups.
Dave
Cory: then the entire expression blows up. But because of the pattern match this will only happen if it overflows Int32, and since the OP was asking to return the values into Int32s, I'm assuming he's happy for it to fail in that scenario (though... the 9e09 in his sample string would overflow Int32... hmm...).
itowlson
@itowlson: maybe I came across a bit harsh--sorry. It just seemed a little too dense for an otherwise simple problem. Don't get me wrong--your approach is elegant in its own way. At a glance, though, it's not at all obvious what this thing does.
Michael Haren
but for those that do use regex a little, it's very clear, which I definitely like.
Dave
@Michael, I beg to differ. This solution is MUCH cleaner than the answer, because if you understand regular expressions (and this one isn't particularly difficult) the intent is very clear.
flq
@itowlson: I think here's a slightly improved regex to the one you had proposed. It has the advantage of dealing with sign, plus you can extract the exponent if necessary: ([-+]?\d+(e[-+]?\d+)?). Oh, and it handles the 9e09 as well, I believe.
Dave
@Frank, @Dave it's not the regex--it's the significantly large chain of operations. Now that it's been reformatted, it is much better. Again, I appreciate the elegance--I love stuff like this--I'm just saying that the iterative approach is more obvious and easier to understand
Michael Haren
Of course if the regex does grow as is inevitable in a public forum like this...it does become part of the problem
Michael Haren
You can get rid of the overflow by using TryParse, also in a LINQ statement, I added it as its own answer.
flq
+2  A: 

The "crazy" Linq way:

    private static IEnumerable<int> GetNumbers(string str)
    {
        foreach (var st in str.Split(new string[]{" "},StringSplitOptions.RemoveEmptyEntries)
            .Where(s => (s.ToCharArray()
                .All(c => Char.IsDigit(c)))))
        {
            yield return Convert.ToInt32(st);
        }
    }
BFree
+1 for craziness ;-)
Cory Charlton
+2  A: 

How about:

int[] xx = raw.Split( ' ' ).Where( ( s, o ) => Int32.TryParse( s, out o ) ).Select( p => Int32.Parse( p ) ).ToArray();
Rus
+2  A: 

In response to itowlson, if somebody is concerned about an overflow, one can also use tryparse in this scenario with the aid of a temporary variable:

int tmp = 0;
var result = (from m in new Regex(@"-?\d+").Matches(s).OfType<Match>()
              let doesParse = int.TryParse(m.Value, out tmp)
              where doesParse
              select tmp).ToList();
flq