C# 中具有模式支持的高级字符串格式化程序

发布于 2025-01-10 06:49:42 字数 616 浏览 1 评论 0原文

我想要一个灵活的模板,可以翻译类似于以下内容的案例:

  • WHnnn => WH001、WH002、WH003...(nnn 只是一个 3 位数字)
  • INVyyyyMMdd => INV20220228
  • ORDERyyyyMMdd-nnn => ORDER20220228-007

我知道我可以使用以下代码来实现特定模板:

string.Format("INV{0:yyyy-MM-dd}", DateTime.Now)

其结果应该与上面的情况 2 相同。但这并不灵活。因为只要我能理解/支持,客户可以定制自己的模板,就像上面的第三种情况。

我知道即使对于第三种情况,我也可以这样做:

string.Format("ORDER{0:yyyy-MM-dd}-{1:d3}", DateTime.Now, 124)

但这很笨拙,因为我希望模板(输入)像这样:

订单yyyyMMdd-nnn

要求是支持 C# 中 string.Format 支持的所有模式,但模板可以是这些模式的任意组合。

I would like to have a flexible template that can translate cases similar to:

  • WHnnn => WH001, WH002, WH003... (nnn is just a number indicated 3 digits)
  • INVyyyyMMdd => INV20220228
  • ORDERyyyyMMdd-nnn => ORDER20220228-007

I know that I can use the following code to achieve a specific template:

string.Format("INV{0:yyyy-MM-dd}", DateTime.Now)

Which should have the same result as case 2 above. But that's not flexible. As the customer may customize their own template as long as I can understand/support, like the third case above.

I know even for the third case, I can do something like this:

string.Format("ORDER{0:yyyy-MM-dd}-{1:d3}", DateTime.Now, 124)

But that's clumsy, as I would like the template (input) to be just like this:

ORDERyyyyMMdd-nnn

The requirement is to support all the supported patterns by string.Format in C#, but the template can be any combination of those patterns.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

比忠 2025-01-17 06:49:42

对于这种情况,我可能会使用自定义格式化程序。

创建一个新类,其中包含日期/时间和日期/时间。 number 并将实现 IFormattable 接口。

有一个提示:使用 INV{nnn}INV[nnn] 样式的某种内部格式,其中仅 { 中的部分}[] 将被替换为该值。

否则可能会出现不需要的更改,例如 Inv contains 'n'。您可以获得 I7v 的输出。

在您的示例中,N 是大写的,但即使在每次自定义之后也是如此吗?

代码(简化版):

internal sealed class InvoiceNumberInfo : IFormattable
{
    private static readonly Regex formatMatcher = new Regex(@"^(?<before>.*?)\[(?<code>\w+?)\](?<after>.*)$");

    private readonly DateTime date;

    private readonly int number;

    public InvoiceNumberInfo(DateTime date, int number)
    {
        this.date = date;
        this.number = number;
    }

    public string ToString(string format, IFormatProvider formatProvider)
    {
        var output = format;
        while (true)
        {
            var match = formatMatcher.Match(output);
            if (!match.Success)
            {
                return output;
            }

            output = match.Groups["before"].Value + FormatValue(match.Groups["code"].Value) + match.Groups["after"].Value;
        }
    }

    private string FormatValue(string code)
    {
        if (code[0] == 'n')
        {
            var numberFormat = "D" + code.Length.ToString(CultureInfo.InvariantCulture);
            return this.number.ToString(numberFormat);
        }
        else
        {
            return this.date.ToString(code);
        }
    }
}

使用:

internal static class Program
{
    public static void Main(string[] args)
    {
        if (args.Length == 0)
        {
            Console.WriteLine("No format to display");
            return;
        }

        var inv = new InvoiceNumberInfo(DateTime.Now, number: 7);
        foreach (string format in args)
        {
            Console.WriteLine("Format: '{0}' is formatted as {1:" + format + "}", format, inv);
        }
    }
}

和输出:

Format: 'WH[nnn]' is formatted as WH007
Format: 'INV[yyyyMMdd]' is formatted as INV20220227
Format: 'ORDER[yyyyMMdd]-[nnn]' is formatted as ORDER20220227-007

注意 这只是一个简化版本,概念证明。对您的代码使用适当的错误检查。

I would probably use a custom formatter for this case.

Create a new class that will contain date/time & number and will implement IFormattable interface.

There is one tip: use some internal format in style INV{nnn} or INV[nnn] where only the part in {} or [] will be replaced with the value.

Otherwise there could be unwanted changes like in Inv contains 'n'. You could get output as I7v.

In your examples the N is upper case, but will it be the case even after each customisation?

Code (simplified version):

internal sealed class InvoiceNumberInfo : IFormattable
{
    private static readonly Regex formatMatcher = new Regex(@"^(?<before>.*?)\[(?<code>\w+?)\](?<after>.*)
quot;);

    private readonly DateTime date;

    private readonly int number;

    public InvoiceNumberInfo(DateTime date, int number)
    {
        this.date = date;
        this.number = number;
    }

    public string ToString(string format, IFormatProvider formatProvider)
    {
        var output = format;
        while (true)
        {
            var match = formatMatcher.Match(output);
            if (!match.Success)
            {
                return output;
            }

            output = match.Groups["before"].Value + FormatValue(match.Groups["code"].Value) + match.Groups["after"].Value;
        }
    }

    private string FormatValue(string code)
    {
        if (code[0] == 'n')
        {
            var numberFormat = "D" + code.Length.ToString(CultureInfo.InvariantCulture);
            return this.number.ToString(numberFormat);
        }
        else
        {
            return this.date.ToString(code);
        }
    }
}

Use:

internal static class Program
{
    public static void Main(string[] args)
    {
        if (args.Length == 0)
        {
            Console.WriteLine("No format to display");
            return;
        }

        var inv = new InvoiceNumberInfo(DateTime.Now, number: 7);
        foreach (string format in args)
        {
            Console.WriteLine("Format: '{0}' is formatted as {1:" + format + "}", format, inv);
        }
    }
}

And output:

Format: 'WH[nnn]' is formatted as WH007
Format: 'INV[yyyyMMdd]' is formatted as INV20220227
Format: 'ORDER[yyyyMMdd]-[nnn]' is formatted as ORDER20220227-007

NOTE This is only a simplified version, proof of concept. Use proper error checking for your code.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文