【问题标题】:.NET Regex replace chars inside group.NET Regex 替换组内的字符
【发布时间】:2012-12-05 11:30:48
【问题描述】:

我正在使用正则表达式替换(在 .Net 应用程序中)从条形码创建项目 ID。这是我正在使用的正则表达式:

^(?<Bestellnr>\w{6})(?<Pos>\d{3})M(?<Menge>\d{5})P(?<Lfd>\d{3})$

替换字符串是(它有前导空格,但这并不重要):

${Bestellnr}${Pos} ${Lfd}

一个示例输入是:

685774010M00555P002

以上替换的当前结果是:

685774010 002

但是现在我的客户希望我从“Pos”和“Lfd”组中删除前导零,因此结果应该变为:

685774 10   2

编辑:请注意“lfd”组中的两个零被两个空格替换!

我已经尝试了几个小时,但我似乎无法让它工作。我能找到的最佳方法是为前导零创建额外的组,例如:

^(?<Bestellnr>\w{6})(?<PosNull>0*)(?<Pos>\d{1,})M(?<Menge>\d{5})P(?<LfdNull>0*)(?<Lfd>\d{1,})$

但我不知道如何用正确数量的空白替换“空组”。这有可能吗? (直到现在我都认为 Regex 没有什么是不可能的 ;-)

谁能帮忙?

【问题讨论】:

    标签: .net regex replace


    【解决方案1】:

    您可以使用 matchevaluator! 将 0 替换为空格!

    Regex.Replace("685774010M00555P002",
    @"^(?<Bestellnr>\w{6})(?<Pos>\d{3})M(?<Menge>\d{5})P(?<Lfd>\d{3})$",
    m=>m.Groups["Bestellnr"].Value+""+
       Regex.Replace(m.Groups["Pos"].Value,"(?<=^0*)0"," ")+
       " "+
       Regex.Replace(m.Groups["Lfd"].Value,"(?<=^0*)0"," "));
    

    【讨论】:

    • 谢谢 Some1,但我更喜欢“纯”替换的解决方案(所以我不必更改代码,只需更改可配置的正则表达式)
    • @Abagneele 仅使用正则表达式是不可能的...您必须为此使用委托..有no other way..
    • 在这里回答 Some1.Kill.The.DJ 和 @GaryH 因为他们的答案几乎相同:好的,从技术上讲,这是一个简单的解决方案。但我不喜欢的是我必须在我的代码中引用命名组。现在,如果客户决定更改组名(无论出于何种原因,请记住它是可配置的),我会遇到问题。这可以更优雅地完成(通过不引用我无法控制的名称)吗?
    • 你可以参考那些编号为$1的组为Bestellnr组等等
    • 是的,但是我将依赖于组的 order,这并没有让它变得更好(甚至更糟......)
    【解决方案2】:

    试试这个:

    string input = "685774010M00555P002";
    
    input = Regex.Replace(input, 
        @"^(?<Bestellnr>\w{6})0*(?<Pos>\d{1,3})M(?<Menge>\d{5})P0*(?<Lfd>\d{1,3})$", 
        m => m.Groups["Bestellnr"].Value + 
             m.Groups["Pos"].Value.PadLeft(3, ' ') + 
             m.Groups["Lfd"].Value.PadLeft(4, ' '));
    

    结果:

    input = "685774 10   2"
    

    编辑: 保留与以前相同的正则表达式,但更改了替换

    另一个编辑:

    您可以完全删除组名并按编号引用它们:

    input = Regex.Replace(input, 
    @"^(\w{6})0*(\d{1,3})M(\d{5})P0*(\d{1,3})$", 
    m => m.Groups[1].Value + 
         m.Groups[2].Value.PadLeft(3, ' ') + 
         m.Groups[4].Value.PadLeft(4, ' '));
    

    注意:m.Groups[0] 指的是整个匹配

    【讨论】:

    • 谢谢 gary,但我需要用 两个 空格替换两个前导零(以及三个空格替换三个零,等等......)
    • 啊,好的。我会再想一想。
    • 正如@Some1.Kill.The.DJ 所说,您需要在替换中使用代表 - 只需使用string.PadLeft() 填充空格
    【解决方案3】:

    好的,找到了适合我需要的解决方案。它是通过一个简单的 String.Format 完成的,将 Regex 的 Groups 传递给它转换为 int。组是通过索引访问的,但由于它是在格式字符串中完成的,因此不需要硬编码。

    代码如下:

    // both from app.config
    Regex regex = new Regex(@"(?<Bestellnr>\w{6})(?<Pos>\d{3})M(?<Menge>\d{5})P(?<Lfd>\d{3})");
    string format = "   {0,6:d}{1,3:d} {3,3:d}";    
    
    string barcode = "685774010M00555P002";
    
    Match match = regex.Match(barcode);
    if (match.Success)
    {
        var groups = (from Group grp in match.Groups select grp.Value).Skip(1).Select(x => (object)int.Parse(x)).ToArray();
        string s = string.Format(format, groups);
        Console.WriteLine(s);
    }
    

    备注:

    • Skip(1) 是必要的,因为集合中的第一组是完整匹配本身。
    • 需要强制转换为对象,因为 string.format 需要一个 params object[] 数组,并且不能与 int[] 一起使用

    【讨论】:

    • @garyh 我会尽快(从现在起 20 小时)。不过感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-09
    • 1970-01-01
    • 1970-01-01
    • 2013-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多