tags:

views:

298

answers:

7

I got the following :

01.05.03

I need to convert that to 1.5.3

The problem is I cannot only trim the 0 because if I got :

01.05.10

I need to convert that to 1.5.10

So, what's the better way to solve that problem ? Regex ? If so, any regex example doing that ?

+3  A: 

You could split the string on ., then trim the leading 0s on the results of the split, then merge them back together.

I don't know of a way to do this in a single operation, but you could write a function that hides this and makes it look like a single operation. ;)

UPDATE:

I didn't even think of the other guy's regex. Yeah, that will probably do it in a single operation.

FrustratedWithFormsDesigner
+1 for ease of read of resulting code, rather than a regex that would require comments
Miki Watts
+1 I'd prefer this to a regex solution.
dtb
@Miki Watts: Well, the regex solution requires no other comment than the split/loop/join variant: `/* remove leading zeros on build number */`.
Tomalak
+15  A: 

Regex-replace

(?<=^|\.)0+

with the empty string. The regex is:

(?<=     # begin positive look-behind (i.e. "a position preceded by")
  ^|\.   #   the start of the string or a literal dot †
)        # end positive look-behind
0+       # one or more "0" characters

† note that not all regex flavors support variable-length look-behind, but .NET does.

If you expect this kind of input: "00.03.03" and want to to keep the leading zero in this case (like "0.3.3"), use this expression instead:

(?<=^|\.)0+(?=\d)

and again replace with the empty string.


From the comments (thanks Kobi): There is a more concise expression that does not require look-behind and is equivalent to my second suggestion:

\b0+(?=\d)

which is

\b       # a word boundary (a position between a word char and a non-word char) 
0+       # one or more "0" characters
(?=\d)   # positive look-ahead: a position that's followed by a digit

This works because the 0 happens to be a word character, so word boundaries can be used to find the first 0 in a row. It is a more compatible expression, because many regex flavors do not support variable-length look-behind, and some (like JavaScript) no look-behind at all.

Tomalak
Can you give me an example of the c# code that does that with the replace please ?
Melursus
@Melursus: No, because this is *really easy* to find. The official documentation and uncounted websites (including Stack Overflow itself) can give you an example how to use regular expressions in .NET.
Tomalak
`\b0+(?=\d)` will also work nicely here, and keep a single zero.
Kobi
@Kobi: Nice catch, this is even better than my look-behind.
Tomalak
A: 
string s = "01.05.10";
string newS = s.Replace(".0", ".");
newS = newS.StartsWith("0") ? newS.Substring(1, newS.Length - 1) : newS;

Console.WriteLine(newS);

NOTE: You will have to thoroughly check for possible input combination.

shahkalpesh
This might not work if he had `001.00005.10`, but he didn't specify if that would be possible.
FrustratedWithFormsDesigner
+14  A: 

Expanding on the answer of @FrustratedWithFormsDesigner:

string Strip0s(string s)
{
    return string.Join<int>(".", from x in s.Split('.') select int.Parse(x));
}
dtb
+1 for Linq-ifying it! I keep forgetting that it's possible to do things like that.
FrustratedWithFormsDesigner
+1 nice alternative, though it does not deal with the `"00.03.03"` case (which may or may not occur).
Tomalak
@Tomalak: that's a good point. Let me fix that :-)
dtb
@dtb: Yes, that's better.
Tomalak
+1  A: 

Here's another way you could do what FrustratedWithFormsDesigner suggests:

string s = "01.05.10";
string s2 = string.Join(
    ".",
    s.Split('.')
        .Select(str => str.TrimStart('0'))
        .ToArray()
);

This is almost the same as dtb's answer, but doesn't require that the substrings be valid integers (it would also work with, e.g., "000A.007.0HHIMARK").

UPDATE: If you'd want any strings consisting of all 0s in the input string to be output as a single 0, you could use this:

string s2 = string.Join(
    ".",
    s.Split('.')
        .Select(str => TrimLeadingZeros(str))
        .ToArray()
);

public static string TrimLeadingZeros(string text) {
    int number;
    if (int.TryParse(text, out number))
        return number.ToString();
    else
        return text.TrimStart('0');
}

Example input/output:

00.00.000A.007.0HHIMARK // input
0.0.A.7.HHIMARK         // output
Dan Tao
That's the solution I had before I changed it to `int.Parse`. It fails when a part is made up entirely of `'0'` characters, e.g., `"03.00.10"`.
dtb
@dtb: What do you mean by "fails"? I don't see where the OP specified what should happen in this case. If trailing zeros are to be removed, I would've thought the output of "03.00.10" should be "03..10", which it is. Otherwise, the OP would need to provide slightly more detailed requirements (unless I'm missing something).
Dan Tao
A: 

This looks like it is a date format, if so I would use Date processing code

DateTime time = DateTime.Parse("01.02.03");
String newFormat = time.ToString("d.M.yy");

or even better

String newFormat = time.ToShortDateString();

which will respect you and your clients culture setting.

If this data is not a date then don't use this :)

David Waters
OP stated it's not a date.
dtb
sorry missed the comment. by OP
David Waters
+1  A: 

There's also the old-school way which probably has better performance characteristics than most other solutions mentioned. Something like:

static public string NormalizeVersionString(string versionString)
{
    if(versionString == null)
       throw new NullArgumentException("versionString");

    bool insideNumber = false;    
    StringBuilder sb = new StringBuilder(versionString.Length);
    foreach(char c in versionString)
    {
        if(c == '.')
        {
            sb.Append('.');
            insideNumber = false;
        }
        else if(c >= '1' && c <= '9')
        {
            sb.Append(c);
            insideNumber = true;
        }
        else if(c == '0')
        {
            if(insideNumber)
                sb.Append('0');
        }
    }
    return sb.ToString();
}
C. Dragon 76