5

What's the easiest way to parse a string and extract a number and a letter? I have string that can be in the following format (number|letter or letter|number), i.e "10A", "B5", "C10", "1G", etc.

I need to extract the 2 parts, i.e. "10A" -> "10" and "A".

Update: Thanks to everyone for all the excellent answers

Matt Warren
  • 10,279
  • 7
  • 48
  • 63

6 Answers6

13

Easiest way is probably to use regular expressions.

((?<number>\d+)(?<letter>[a-zA-Z])|(?<letter>[a-zA-Z])(?<number>\d+))

You can then match it with your string and extract the value from the groups.

Match match = regex.Match("10A");
string letter = match.Groups["letter"].Value;
int number = int.Parse(match.Groups["number"].Value);
Samuel
  • 37,778
  • 11
  • 85
  • 87
6

The easiest and fastest is to use simple string operations. Use the IsDigit method to check where the letter is, and parse the rest of the string to a number:

char letter = str[0];
int index = 1;
if (Char.IsDigit(letter)) {
   letter = str[str.Length - 1];
   index = 0;
}
int number = int.Parse(str.Substring(index, str.Length - 1));
Guffa
  • 687,336
  • 108
  • 737
  • 1,005
4

Just to be different:

string number = input.Trim("ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray());
string letter = input.Trim("0123456789".ToCharArray());
Daniel LeCheminant
  • 50,583
  • 16
  • 120
  • 115
4
char letter = str.Single(c => char.IsLetter(c));
int num = int.Parse(new string(str.Where(c => char.IsDigit(c)).ToArray()));

This solution is not terribly strict (it would allow things like "5A2" and return 'A' and 52) but it may be fine for your purposes.

mqp
  • 70,359
  • 14
  • 95
  • 123
1

Here is how I would approach this. You can step through this and put gc1["letter"], gc1["number"], gc2["letter"], and gc2["number"] in the watch window to see that it worked (step just past the last line of code here, of course).

The regular epxression will take either pattern requiring one or more letter and number in each case.

        Regex pattern = new Regex("^(?<letter>[a-zA-Z]+)(?<number>[0-9]+)|(?<number>[0-9]+)(?<letter>[a-zA-Z]+)$");
        string s1 = "12A";
        string s2 = "B45";
        Match m1 = pattern.Match(s1);
        Match m2 = pattern.Match(s2);
        GroupCollection gc1 = m1.Groups;
        GroupCollection gc2 = m2.Groups;
Rich
  • 36,270
  • 31
  • 115
  • 154
  • 1
    If you're going to pretty much copy my answer, at least get the regex right. It should be [a-zA-Z], with no plus. – Samuel Apr 09 '09 at 16:50
0

Using Sprache and some Linq kung-fu:

var tagParser =
    from a in Parse.Number.Or(Parse.Letter.Once().Text())
    from b in Parse.Letter.Once().Text().Or(Parse.Number)
    select char.IsDigit(a[0]) ?
           new{Number=a, Letter=b} : new{Number=b, Letter=a};

var tag1 = tagParser.Parse("10A");
var tag2 = tagParser.Parse("A10");

tag1.Letter; // should be A 
tag1.Number; // should be 10

tag2.Letter; // should be A
tag2.Number; // should be 10

/* Output:
   A
   10
   A
   10
 */
Brian Chavez
  • 8,048
  • 5
  • 54
  • 47