views:

169

answers:

5

I have a very simple question, and I shouldn't be hung up on this, but I am. Haha!

I have a string that I receive in the following format(s):

123

123456-D53

123455-4D

234234-4

123415

The desired output, post formatting, is:

123-455-444

123-455-55

123-455-5

or

123-455

The format is ultimately dependent upon the total number of characters in the original string..

I have several ideas of how to do this, but I keep thing there's a better way than string.Replace and concatenate...

Thanks for the suggestions..

Ian

+2  A: 

EDIT: See history for old versions.
You could use char.IsDigit() for finding digits, only.

var output = new StringBuilder();
var digitCount = 0;

foreach( var c in input )
{
  if( char.IsDigit( c ) )
  {
    output.Append( c );
    digitCount++;
    if( digitCount % 3 == 0 )
    {
      output.Append( "-" );
    }
  }
}

// Remove possible last -
return output.ToString().TrimEnd('-');

This code should fill from left to right (now I got it, first read, then code) ...
Sorry, I still can't test this right now.

tanascius
I am about to clarify my original post, the string can be alphanumeric, not just numeric.
Ian P
I think this fills the numbers in the wrong direction. He wants it Left-Justified, so to speak.
sixlettervariables
@Ian: I use char.IsDigit, now. @sixlettervariables: you are right, that makes it a lot more difficult.
tanascius
@Ian: My solution removes letters, now ... hope you wanted this, because it is not clear from your question (all outputs have numbers, only)
tanascius
I'm not on newest .Net so this may have been changed, but shouldn't `== "-"` be replaced with `== '-'`?
Brian
instead of your last if you could simply dooutput = output.TrimEnd('-');
Rune FS
@Brian: Thanks, that's the simple stuff I didn't find without a compiler :/
tanascius
@Rune FS/tanascius: Since remove doesn't work on .Net 2.0, I'll assume it doesn't work on newer .Net. I replaced it with a return using Rune FS's change.
Brian
@Brian: Thanks for the edit ... looks cleaner, now
tanascius
+2  A: 

I assume this does not merely rely upon the inputs always being numeric? If so, I'm thinking of something like this

private string ApplyCustomFormat(string input)
{
    StringBuilder builder = new StringBuilder(input.Replace("-", ""));

    int index = 3;
    while (index < builder.Length)
    {
        builder.Insert(index, "-");
        index += 4;
    }
    return builder.ToString();
}
Anthony Pegram
This is similar to my implementation.. I'm just caught up on the "is this the most efficient way to do this?" question..
Ian P
@Ian P -- "most efficient" is less important than "efficient enough". See the first comment. I would be tempted to write "less efficient" code that uses an IEnumerable chunker (method or Regex) and String.Join ;-)
pst
Picked this one as the answer, as it worked first per the spec I describe. Although, the other posters updated their code to work as required as well. All are worthy of green checkmarks, but I can only give one :)
Ian P
+4  A: 

Tanascius is right but I cant comment or upvote due to my lack of rep but if you want additional info on the string.format Ive found this helpful. http://blog.stevex.net/string-formatting-in-csharp/

Ryan Dunn
Great link, thanks.
Ian P
@Ryan. I should have let you know that I deleted my answer :-). The OP changed the question and it no longer applies. Besides, sixlettervariable pointed out that it actually does not answer the original question too.
Moron
A: 

Not the fastest, but easy on the eyes (ed: to read):

string Normalize(string value)
{
    if (String.IsNullOrEmpty(value)) return value;

    int appended = 0;
    var builder = new StringBuilder(value.Length + value.Length/3);
    for (int ii = 0; ii < value.Length; ++ii)
    {
        if (Char.IsLetterOrDigit(value[ii]))
        {
            builder.Append(value[ii]);
            if ((++appended % 3) == 0) builder.Append('-');
        }
    }

    return builder.ToString().TrimEnd('-');
}

Uses a guess to pre-allocate the StringBuilder's length. This will accept any Alphanumeric input with any amount of junk being added by the user, including excess whitespace.

sixlettervariables
Haha, we must have different types of eyes :p
pst
You should be checking for `(ii + 1) % 3 == 0`.
0xA3
@0xA3: good catch. @pst: if I'm coming back through to read this, it'll be obvious what's going on. No obfuscation ;)
sixlettervariables
You updated the code, but it is still wrong ;-) So either check for `((builder.Length+ 1) % 4) == 0` or for `((ii + 1) % 3 == 0)`.
0xA3
+2  A: 

Here's a method that uses a combination of regular expressions and LINQ to extract groups of three letters at a time and then joins them together again. Note: it assumes that the input has already been validated. The validation can also be done with a regular expression.

string s = "123456-D53";
string[] groups = Regex.Matches(s, @"\w{1,3}")
                       .Cast<Match>()
                       .Select(match => match.Value)
                       .ToArray();
string result = string.Join("-", groups);

Result:

123-456-D53
Mark Byers