.Net 移除字符串开头的所有 0

7

我得到了以下内容:

01.05.03

我需要将其转换为1.5.3

问题在于我不能只裁剪0,因为如果我得到:

01.05.10

我需要将其转换为1.5.10

那么怎样更好地解决这个问题呢?是使用正则表达式吗?如果是,有没有做到这一点的正则表达式示例?


你正在尝试格式化日期吗?有比正则表达式更好的方法来做这件事情。 - Oded
2
不是日期,而是层次结构水平。 - Melursus
8个回答

16

扩展 @FrustratedWithFormsDesigner 的答案:

string Strip0s(string s)
{
    return string.Join<int>(".", from x in s.Split('.') select int.Parse(x));
}

1
+1 为 Linq-化它!我总是忘记可以做那样的事情。 - FrustratedWithFormsDesigner
1
+1 不错的替代方案,尽管它不能处理 "00.03.03" 的情况(可能会出现,也可能不会出现)。 - Tomalak

15

正则表达式替换

(?<=^|\.)0+
使用空字符串。正则表达式如下:
(?<=     # 开始正向先行断言(即“由...前导的位置”)
  ^|\.   #   字符串的开头或一个字面点 †
)        # 结束正向先行断言
0+       # 一个或多个字符“0”

† 注意,并非所有的正则表达式支持变长后行断言,但 .NET 支持。

如果您期望此类输入:"00.03.03"并希望在这种情况下保留前导零(如"0.3.3"),请改用以下表达式:
(?<=^|\.)0+(?=\d)

并再次替换为空字符串。


来自评论(感谢Kobi):有一个更简练的表达式,不需要使用回顾断言,等价于我的第二个建议:

\b0+(?=\d)

这段代码的作用是

\b       # 一个单词边界(在一个单词字符和非单词字符之间的位置)
0+       # 一个或多个“0”字符
(?=\d)   # 正向先行断言:一个紧跟着数字的位置

它有效的原因是因为 0 恰好是一个单词字符,所以可以使用单词边界来找到连续一串中的第一个0。这样的表达式更加兼容,因为许多正则表达式不支持可变长度后行断言,并且有些语言(如 JavaScript)根本不支持后行断言。


请给我一个使用replace函数实现该功能的C#代码示例。 - Melursus
4
@Melursus:不需要,因为这非常容易找到。官方文档和无数网站(包括 Stack Overflow 本身)都可以给你提供在 .NET 中使用正则表达式的示例。 - Tomalak
1
\b0+(?=\d) 在这里也可以很好地工作,并保持单个零。 - Kobi
@Kobi:很好的发现,这比我的后顾之忧还要好。 - Tomalak

3
你可以用 split 函数在点号处分割字符串,然后去掉分割结果中前面的 0,最后再将它们合并起来。
我不知道有没有一种方法可以一次性完成这个操作,但你可以编写一个函数来隐藏这些步骤,使其看起来像是一次操作。 ;)
更新:
我甚至没有想到另一个人的正则表达式。是的,那可能会在一次操作中完成。

返回已翻译的文本:对于代码易读性的便利性,使用+1而不是需要注释的正则表达式。 - Miki Watts
@Miki Watts:正则表达式的解决方案不需要其他注释,只需使用split/loop/join变体:/* 删除构建号前导零 */ - Tomalak

1

这里是另一种实现 FrustratedWithFormsDesigner 建议的方法:

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

这与dtb的答案几乎相同,但不要求子字符串是有效的整数(例如,它也可以使用“000A.007.0HHIMARK”)。

更新:如果您希望将输入字符串中所有0组成的任何字符串输出为单个0,则可以使用此代码:

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');
}

示例输入/输出:

00.00.000A.007.0HHIMARK // input
0.0.A.7.HHIMARK         // output

这是我在改用int.Parse之前的解决方案。当某个部分完全由'0'字符组成时,例如"03.00.10",它会失败。 - dtb
@dtb:你所说的“失败”是什么意思?我没有看到原帖中指定了在这种情况下应该发生什么。如果要删除尾随零,则认为“03.00.10”的输出应为“03..10”,而实际上确实如此。否则,原帖作者需要提供稍微详细一些的要求(除非我漏掉了什么)。 - Dan Tao

1

还有一种老派的方法,可能比其他提到的解决方案具有更好的性能特征。类似这样:

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();
}

0
string s = "01.05.10";
string newS = s.Replace(".0", ".");
newS = newS.StartsWith("0") ? newS.Substring(1, newS.Length - 1) : newS;

Console.WriteLine(newS);

注意:您需要彻底检查可能的输入组合。


1
这可能不适用于他的 001.00005.10,但他没有说明是否可能。 - FrustratedWithFormsDesigner

0

这看起来像是一个日期格式,如果是的话,我会使用日期处理代码

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

或者更好的是
String newFormat = time.ToShortDateString();

它将尊重您和您客户的文化设置。

如果这个数据不是一个日期,那就别用它 :)


抱歉,我错过了原始发布者的评论。 - David Waters

0
我有一个类似的需求,需要解析包含街道地址的字符串,其中一些房屋号码具有前导零,我需要去掉它们,同时保持其余文本不变,因此我稍微编辑了已接受的答案以满足我的要求,也许有人会发现它有用。基本上和接受的答案做相同的事情,不同之处在于我检查字符串部分是否可以解析为整数,并在为false时将其默认为字符串值;
string Strip0s(string s)
{
    int outputValue;
    return
        string.Join(" ",
            from x in s.Split(new[] { ' ' })
            select int.TryParse(x, out outputValue) ? outputValue.ToString() : x);
}

输入: "Islands Brygge 34 B 07 TV" 输出: "Islands Brygge 34 B 7 TV"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接