【问题标题】:Conditional regex replace if value less than "nnnn"如果值小于“nnnn”,则条件正则表达式替换
【发布时间】:2009-08-19 06:49:09
【问题描述】:

不确定这是否可以使用正则表达式替换命令,但我有一个现有的正则表达式替换,它将数字的最后两位数字转换为以句号为前缀的相同最后两位数字。这是为了与通过货币值发送为“2500”的系统连接,其中这表示“25.00”美元。

我现有的正则表达式:(\d+)(\d{2})$
替换语法为:$1.$2

现在我有一个问题,如果一个值仅作为“50”发送,这可能表示 0.50,我的正则表达式将失败,因为它在左侧搜索 1+ 数字,而两个数字正好在字符串的结尾。

我怎样才能涵盖所有这些情况并让我的正则表达式替换替换:

2500 = 25.00
500 = 5.00
50 = 0.50
5 = 0.05

再次感谢, 格雷厄姆

更新:对于那些问为什么这不能是一个分割和字符串格式的工作的人是因为我必须避免自定义编程来实现这一点。理想情况下,它必须是在数据库中定义的正则表达式“规则”以及其他正则表达式定义,因为它被用于通用翻译系统。它将转换可能有多种格式类型的传入数据,例如通常将字段从“101”转换为“101A”,但在这种数据类型的特殊情况下,需要添加值。

第二次更新:我一直在思考这个问题,因为我绑定到一个数据库,有人会看到比使用 %wackyMoney% 或在 db 字段中定义的其他一些“令牌”更好的方法吗?然后测试我们是否在代码中点击了这个标记以应用 C# 字符串格式和除法?

【问题讨论】:

    标签: .net regex


    【解决方案1】:

    .Net 正则表达式可以使用匹配评估器将匹配转换为所需的任何内容:

    String result = Regex.Replace(
       "test 1 test 20 test 300 test 4000 test 50000",
       @"\d+",
       (match => (Double.Parse(match.Value) / 100).ToString("0.00")));
    

    结果是:

    test 0.01 test 0.20 test 3.00 test 40.00 test 500.00
    

    【讨论】:

    • 这个答案让我朝着正确的方向前进。我的目标是修复任何格式错误的日期,这些日期应该从月份开始,但偶尔会从当天开始。我的方法只有在月份大于 12 时才需要交换月份和日期。
    【解决方案2】:

    你为什么要为此使用正则表达式?!使用 single 正则表达式不会有一个简单的方法来做到这一点,但你可以用几个来做到这一点(一个用于 3+ 位数的情况,一个用于 2 位数的情况,一个对于 1 位数的情况)。但是……

    我不知道确切的 C# 语法,但大致如下:

    sprintf('%0.2f', «var»/100.0)
    

    只要你的数字足够小,你的浮点类型精确到优于 0.01,它似乎就会完全按照你的意愿去做。对于双打来说,这已经是千万亿了。

    编辑 1

    因为你需要正则表达式,你可以使用三个(这里是 Perl 语法,但是...):

    s/^(\d+)(\d{2})$/$1.$2/;   # you already have this
    s/^(\d{2})$/0.$1/;         # obvious variant 1
    s/^(\d{1}$/0.0$1/;         # obvious variant 2
    

    其中只有一个会匹配(变体 1 需要 3+ 个字符,变体 2 正好需要 2 个字符,变体 3 正好需要 1 个字符),因此如果您可以附加多个正则表达式,则可以使用它。我可以将所有这些都放入 Perl 中的一个正则表达式中,但我不知道您是否具有完整的 Perl 正则表达式功能(我对此表示怀疑)。毕竟,Perl 可以做到:

    s/^(\d+)$/sprintf('%0.2f', $1/100.0)/e
    

    但那相当作弊。你的正则表达式引擎有类似的东西吗?或者你说这是一个数据库的东西;你可以使用 SQL 的CASE 条件吗?

    【讨论】:

    • 正在使用正则表达式,因为这是用于通用翻译系统,并且在数据库中为一组传入数据定义了翻译规则,我知道在正常情况下很奇怪。但这不正常:)
    • 哇,很好的反应。我正在使用 .NET 正则表达式引擎,但我认为我们不能像这样在正则表达式中调用命令!会好的。我认为,但是你肯定可以使用分号分隔的正则表达式集,如果我不能做多行,我绝对有能力更改正则表达式解析器以用分号解析多个正则表达式集开箱即用,将看看 - 非常感谢。
    • 很高兴听到我的帮助。
    【解决方案3】:

    正则表达式无法创建不存在的内容,因此您无法添加不存在的零。所以答案是你不应该为此使用正则表达式。

    最好的办法是使用(Double.Parse(value) / 100).ToString("0.00") 或类似的。


    由于您想要在数据库中定义通用规则集,我认为这里的错误是您将数字规则与字符串规则混合在一起。您可能应该让您的数据库支持不同类型的规则。

    我认为您应该有一个额外的列来指定该值应该以数字方式还是字符串形式进行修改。如果应该以数字方式对其进行修改,您可以让当前用于替换的列指定一个乘数或类似的值。

    如果你想更进一步,你可以有一个简单的公式评估器,它可以像这样:x / 100 + " USD"。 .NET 已经有很多可用的了,而且自己制作一个简单的也不是很难。

    【讨论】:

    • 我以为是这样,内容必须先存在。我会考虑一下,但是当我回复 derobert 的消息时,理想情况下它必须是一个通用的、未编程的 db 定义的处理程序。
    【解决方案4】:

    您是否有理由不将字符串转换为数字,除以 100,然后再转换回具有适当格式的字符串?

    【讨论】:

      【解决方案5】:

      这可能无法准确回答操作员的问题,但它可以为您提供一些关于如何根据条件利用匹配参数的想法。

      如果月份大于 12,以下方法将交换日期的日和月部分。
      示例:

      string myStr = "14/3/2018";
      string newStr = MDYToDMY(myStr);
      Console.WriteLine(newStr); // prints "3/14/2018"
      
          static string MDYToDMY(string input)
          {
              try
              {
                  return Regex.Replace(input,
                      "\\b(?<month>\\d{1,2})/(?<day>\\d{1,2})/(?<year>\\d{2,4})\\b",
                      (match => (int.Parse(match.Groups["month"].Value) > 12) 
                          ? $"{match.Groups["day"]}/{match.Groups["month"]}/{match.Groups["year"]}" 
                          : $"{match.Groups["month"]}/{match.Groups["day"]}/{match.Groups["year"]}"),
                      RegexOptions.None,
                      TimeSpan.FromMilliseconds(150));
              }
              catch (RegexMatchTimeoutException)
              {
                  return input;
              }
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-10-16
        • 2012-01-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-07
        • 2012-06-10
        相关资源
        最近更新 更多