1

I have the following string "23456789"
and I need it to become "23 456 789".

I found this:

Regex.Replace(MYString, ".{3}", "$0 ");

but the number becomes "234 567 89".

It doesnt have to be Regex, everything is welcomed. Thank you

bobble bubble
  • 16,888
  • 3
  • 27
  • 46
Mitko Kotev
  • 65
  • 1
  • 8
  • 1
    Multiple examples of the string conversion would help, do you always want it to be a 2-digit 3-digit 3-digit split? – Callum Bradbury Jan 22 '16 at 10:27
  • 1
    Are you trying to convert a money value into a string with spaces between the thousand groups? – Steve Jan 22 '16 at 10:28
  • i think the key term here is splitting "from right to left" – user1666620 Jan 22 '16 at 10:28
  • What if you reverse your string apply your regex and then reverse it back? – croxy Jan 22 '16 at 10:29
  • Possible duplicate of [How would I separate thousands with space in C#](http://stackoverflow.com/questions/17527847/how-would-i-separate-thousands-with-space-in-c-sharp) – Fred Jan 22 '16 at 10:43

7 Answers7

3

You could parse it to decimal and use a custom NumberFormatInfo with space as group-separator:

string input = "23456789";
decimal d = decimal.Parse(input);
var nfi = (NumberFormatInfo)CultureInfo.InvariantCulture.NumberFormat.Clone();
nfi.NumberGroupSeparator = " ";
nfi.NumberDecimalDigits = 0;
string formatted= d.ToString("N", nfi);  

See: The Numeric ("N") Format Specifier

For what it's worth. Here is an approach which works not only for numeric strings but for all kind of strings and even for any kind of objects(if you remove the string.Join):

string result = String.Join(" ", input.Reverse()  // reverse input to get proper groups from right to left
    .Select((c, index) => new { Char = c, Index = index })
    .GroupBy(x => x.Index / 3, x=> x.Char) // group by index using integer division and then output the char
    .Reverse() // again reverse to get original order
    .Select(charGroup => new String(charGroup.Reverse().ToArray())));
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
0

Tim answer will works for decimal values but for really big numbers there is more generic solution. Note that it's performance killer because we are declaring new arrays and copy data few times:

string myString = "95555554643674373734737443737";
// revert source string
string reversedList = new string(myString.Reverse().ToArray());
// replace each trio
string replacedReversedList = Regex.Replace(reversedList, ".{3}", "$0 ");
// revert replaced string back to normal direction
string result = new string(replacedReversedList.Reverse().ToArray());

string oneLineResult = new string(Regex.Replace(new string(myString.Reverse().ToArray()), ".{3}", "$0 ").Reverse().ToArray());
Community
  • 1
  • 1
Vadim Martynov
  • 8,602
  • 5
  • 31
  • 43
0

Doesn't need to parse/format anything or multiple loops (like Reverse, ToArray, etc):

private static String CreateGroups(string source, int groupSize)
{
    if (groupSize <= 0)
        throw new ArgumentOutOfRangeException("groupSize", "must be greater zero.");

    var sb = new StringBuilder();
    var firstGroupLength = source.Length % groupSize;
    var groupLength = firstGroupLength == 0 ? groupSize : firstGroupLength;

    foreach (var item in source)
    {
        sb.Append(item);
        groupLength--;

        if (groupLength == 0)
        {
            groupLength = groupSize;
            sb.Append(' ');
        }
    }

    return sb.ToString(0, sb.Length-1);
}
Oliver
  • 43,366
  • 8
  • 94
  • 151
0

use this code add namespace using System.Globalization;

var nfi = (NumberFormatInfo)CultureInfo.InvariantCulture.NumberFormat.Clone();
            nfi.NumberGroupSeparator = " ";

            string formatted = 23456789m.ToString("#,#", nfi);
0

I'd just do this for the general case:

string test = "23456789";
int n = 3; // Or whatever grouping you want.

for (int i = test.Length - n; i > 0; i -= n)
    test = test.Insert(i, " ");

Console.WriteLine(test);

But if you are really trying to format a number rather than a string, I'd go with one of the other number-based answers in this thread.

Matthew Watson
  • 104,400
  • 10
  • 158
  • 276
0

This works:

var MyString = "23456789";

var result =
    new string(
        MyString
            .Reverse()
            .SelectMany((x, n) =>
                new [] { x }.Concat(n % 3 == 2
                    ? new [] { ' ' } 
                    : Enumerable.Empty<char>()))
            .Reverse()
            .ToArray());

I get the required "23 456 789".

Enigmativity
  • 113,464
  • 11
  • 89
  • 172
0

Here is my take on it.

This does not require cast to a numerical type and you can vary the size of a chunk

public static string Separate(this string source, int chunkSize = 3)
{
  return string.Concat(source.Select((x, i) => (source.Length - i - 1) % chunkSize == 0 ? x + " " : x.ToString()));
}

Usage:

string str = "23456789";
var separatedBy3 = str.Separate(); //23 456 789

var separatedy4 = str.Separate(4); //2345 6789
bashis
  • 1,200
  • 1
  • 16
  • 35