26

E.g., I would like to separate:

  • OS234 to OS and 234
  • AA4230 to AA and 4230

I have used following trivial solution, but I am quite sure that there should be a more efficient and robust solution .

private void demo()
    {   string cell="ABCD4321";
        int a = getIndexofNumber(cell);
        string Numberpart = cell.Substring(a, cell.Length - a);
        row = Convert.ToInt32(rowpart);
        string Stringpart = cell.Substring(0, a);
    }

private int getIndexofNumber(string cell)
        {
            int a = -1, indexofNum = 10000;
            a = cell.IndexOf("0"); if (a > -1) { if (indexofNum > a) { indexofNum = a; } }
            a = cell.IndexOf("1"); if (a > -1) { if (indexofNum > a) { indexofNum = a; } }
            a = cell.IndexOf("2"); if (a > -1) { if (indexofNum > a) { indexofNum = a; } }
            a = cell.IndexOf("3"); if (a > -1) { if (indexofNum > a) { indexofNum = a; } }
            a = cell.IndexOf("4"); if (a > -1) { if (indexofNum > a) { indexofNum = a; } }
            a = cell.IndexOf("5"); if (a > -1) { if (indexofNum > a) { indexofNum = a; } }
            a = cell.IndexOf("6"); if (a > -1) { if (indexofNum > a) { indexofNum = a; } }
            a = cell.IndexOf("7"); if (a > -1) { if (indexofNum > a) { indexofNum = a; } }
            a = cell.IndexOf("8"); if (a > -1) { if (indexofNum > a) { indexofNum = a; } }
            a = cell.IndexOf("9"); if (a > -1) { if (indexofNum > a) { indexofNum = a; } }

            if (indexofNum != 10000)
            { return indexofNum; }
            else
            { return 0; }


        }

10 Answers 10

37

Regular Expressions are best suited for this kind of work:

using System.Text.RegularExpressions;

Regex re = new Regex(@"([a-zA-Z]+)(\d+)");
Match result = re.Match(input);

string alphaPart = result.Groups[1].Value;
string numberPart = result.Groups[2].Value;
Sign up to request clarification or add additional context in comments.

5 Comments

Might want to add two lines to this answer: string alphaPart = result.Groups[1]; string numberPart = result.Groups[2];
Following seems to be more complete solution: Regex re = new Regex(@"([a-zA-Z]+)(\d+)"); Match result = re.Match("as23"); string alphaPart = result.Groups[1].ToString (); string numberPart = result.Groups[2].ToString();
Isn't it result.Groups[1].Value?
result.Groups[2].ToString(); Worked for me Further we should add Imports Systems.Text.Regularexpression @ top.
"GJ10HE1895" is my string any i want it like GJ,10,HE, 1895 seperately in different group can you suggest solution. @x0n
13

Use Linq to do this

string str = "OS234";

var digits = from c in str
             select c
             where Char.IsDigit(c);

var alphas = from c in str
             select c
             where !Char.IsDigit(c);

2 Comments

This seems to be good solution ,but unfortunately .net 2.0 users could not use Linq
I recomend - upgrade to C# 3.0.
6

Everyone and their mother will give you a solution using regex, so here's one that is not:

 // s is string of form ([A-Za-z])*([0-9])* ; char added
 int index = s.IndexOfAny(new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' });
 string chars = s.Substring(0, index);
 int num = Int32.Parse(s.Substring(index));

1 Comment

You got regex problems? I feel bad for you son. I got 99 problems but a Regex ain't one.
6

I really like jason's answer. Lets improve it a bit. We dont need regex here. My solution handle input like "H1N1":

public static IEnumerable<string> SplitAlpha(string input)
{
    var words = new List<string> { string.Empty };
    for (var i = 0; i < input.Length; i++)
    {
        words[words.Count-1] += input[i];
        if (i + 1 < input.Length && char.IsLetter(input[i]) != char.IsLetter(input[i + 1]))
        {
            words.Add(string.Empty);
        }
    }
    return words;
}

This solution is linear O(n).

output

"H1N1" -> ["H", "1", "N", "1"]
"H" -> ["H"]
"GH1N12" -> ["GH", "1", "N", "12"]
"OS234" -> ["OS", "234"]

Same solution with a StringBuilder

public static IEnumerable<string> SplitAlpha(string input)
{
    var words = new List<StringBuilder>{new StringBuilder()};
    for (var i = 0; i < input.Length; i++)
    {
        words[words.Count - 1].Append(input[i]);
        if (i + 1 < input.Length && char.IsLetter(input[i]) != char.IsLetter(input[i + 1]))
        {
            words.Add(new StringBuilder());
        }
    }

    return words.Select(x => x.ToString());
}

Try it Online!

1 Comment

@DJBurb Glad I could be useful :)
4

If you want resolve more occurrences of char followed by number or vice versa you can use

private string SplitCharsAndNums(string text)
{
    var sb = new StringBuilder();
    for (var i = 0; i < text.Length - 1; i++)
    {
        if ((char.IsLetter(text[i]) && char.IsDigit(text[i+1])) ||
            (char.IsDigit(text[i]) && char.IsLetter(text[i+1])))
        {
            sb.Append(text[i]);
            sb.Append(" ");
        }
        else
        {
            sb.Append(text[i]);
        }
    }

    sb.Append(text[text.Length-1]);

    return sb.ToString();
}

And then

var text = SplitCharsAndNums("asd1 asas4gr5 6ssfd");
var tokens = text.Split(' ');

1 Comment

Works well until you meet a non-letter or numeric, such as a . in a file name. Change char.IsLetter to !char.IsNumeric
1

Are you doing this for sorting purposes? If so, keep in mind that Regex can kill performance for large lists. I frequently use an AlphanumComparer that's a general solution to this problem (can handle any sequence of letters and numbers in any order). I believe that I adapted it from this page.

Even if you're not sorting on it, using the character-by-character approach (if you have variable lengths) or simple substring/parse (if they're fixed) will be a lot more efficient and easier to test than a Regex.

Comments

1

I have used bniwredyc's answer to get Improved version of my routine:

    private void demo()
        {
            string cell = "ABCD4321";
            int row, a = getIndexofNumber(cell);
            string Numberpart = cell.Substring(a, cell.Length - a);
            row = Convert.ToInt32(Numberpart);
            string Stringpart = cell.Substring(0, a);
        }

        private int getIndexofNumber(string cell)
        {
            int indexofNum=-1;
            foreach (char c in cell)
            {
                indexofNum++;
                if (Char.IsDigit(c))
                {
                    return indexofNum;
                }
             }
            return indexofNum;
        }

Comments

1

.NET 2.0 compatible, without regex

public class Result
{
    private string _StringPart;
    public string StringPart
    {
        get { return _StringPart; }
    }

    private int _IntPart;
    public int IntPart
    {
        get { return _IntPart; }
    }

    public Result(string stringPart, int intPart)
    {
        _StringPart = stringPart;
        _IntPart = intPart;
    }
}

class Program
{
    public static Result GetResult(string source)
    {
        string stringPart = String.Empty;
        int intPart;
        var buffer = new StringBuilder();
        foreach (char c in source)
        {
            if (Char.IsDigit(c))
            {
               if (stringPart == String.Empty)
               {
                    stringPart = buffer.ToString();
                    buffer.Remove(0, buffer.Length);
                }
            }

            buffer.Append(c);
        }

        if (!int.TryParse(buffer.ToString(), out intPart))
        {
            return null;
        }

        return new Result(stringPart, intPart); 
    }

    static void Main(string[] args)
    {
        Result result = GetResult("OS234");
        Console.WriteLine("String part: {0} int part: {1}", result.StringPart, result.IntPart);
        result = GetResult("AA4230 ");
        Console.WriteLine("String part: {0} int part: {1}", result.StringPart, result.IntPart);
        result = GetResult("ABCD4321");
        Console.WriteLine("String part: {0} int part: {1}", result.StringPart, result.IntPart);
        Console.ReadKey();
    }
}

1 Comment

@this.__curious_geek yep. I like Jasons solution.
-2

Just use the substring function and set position inside the bracket.

 String id = "DON123";
 System.out.println("Id nubmer is : "+id.substring(3,6));

Answer:

 Id number is: 123

1 Comment

The string is not the same length each time, nor the number of characters or digits
-3

use Split to seprate string from sting that use tab \t and space

string s = "sometext\tsometext\tsometext";
string[] split = s.Split('\t');

now you have an array of string that you want too easy

1 Comment

this answer is irrelevant to the question, it's not about separating number from letters at all. also your "too easy" in the end sounds spiteful, author wouldn't ask question if that was as easy as this answer states

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.