C# 中具有模式支持的高级字符串格式化程序
Advanced string formatter with pattern support in C#
我想要一个灵活的模板,可以翻译类似于以下的案例:
- WHnnn => WH001, WH002, WH003...(nnn 只是一个表示 3 位的数字)
- INVyyyyMMdd => INV20220228
- ORDERyyyyMMdd-nnn => ORDER20220228-007
我知道我可以使用下面的代码来实现特定的模板:
string.Format("INV{0:yyyy-MM-dd}", DateTime.Now)
这应该与上述情况 2 具有相同的结果。但这并不灵活。由于客户可以定制自己的模板,只要我可以understand/support,就像上面的第三种情况
我知道即使是第三种情况,我也可以这样做:
string.Format("ORDER{0:yyyy-MM-dd}-{1:d3}", DateTime.Now, 124)
但这很笨拙,因为我希望模板(输入)是这样的:
ORDERyyyyMMdd-nnn
要求是在 C# 中支持 string.Format 支持的所有模式,但模板可以是这些模式的任意组合。
对于这种情况,我可能会使用自定义格式化程序。
创建一个新的 class,它将包含 date/time & 号码并将实现 IFormattable
接口。
有一个提示:在样式INV{nnn}
或INV[nnn]
中使用一些内部格式,其中只有{}
或[=中的部分17=] 将替换为值。
否则可能会有不需要的更改,例如 Inv 包含 '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
注意 这只是一个简化版本,概念证明。对您的代码使用适当的错误检查。
我想要一个灵活的模板,可以翻译类似于以下的案例:
- WHnnn => WH001, WH002, WH003...(nnn 只是一个表示 3 位的数字)
- INVyyyyMMdd => INV20220228
- ORDERyyyyMMdd-nnn => ORDER20220228-007
我知道我可以使用下面的代码来实现特定的模板:
string.Format("INV{0:yyyy-MM-dd}", DateTime.Now)
这应该与上述情况 2 具有相同的结果。但这并不灵活。由于客户可以定制自己的模板,只要我可以understand/support,就像上面的第三种情况
我知道即使是第三种情况,我也可以这样做:
string.Format("ORDER{0:yyyy-MM-dd}-{1:d3}", DateTime.Now, 124)
但这很笨拙,因为我希望模板(输入)是这样的:
ORDERyyyyMMdd-nnn
要求是在 C# 中支持 string.Format 支持的所有模式,但模板可以是这些模式的任意组合。
对于这种情况,我可能会使用自定义格式化程序。
创建一个新的 class,它将包含 date/time & 号码并将实现 IFormattable
接口。
有一个提示:在样式INV{nnn}
或INV[nnn]
中使用一些内部格式,其中只有{}
或[=中的部分17=] 将替换为值。
否则可能会有不需要的更改,例如 Inv 包含 '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
注意 这只是一个简化版本,概念证明。对您的代码使用适当的错误检查。