【问题标题】:Format string with meaningful markers使用有意义的标记格式化字符串
【发布时间】:2018-03-16 12:41:50
【问题描述】:

我使用了一个模板字符串,从数据库和/或文本文件中读取:

var template="Your order {0} has dispatched from {1}, ETA {2:HH:MM dd.MM.yyyy}";

然后用string.Format(template, orderNo, warehouse, eta) 注入正确的值。

现在,我们做出了一项业务决策,即更改这些模板以使用更有意义的标记:

var template="Your order {orderNo} has dispatched from {warehouse}, ETA {eta:HH:MM dd.MM.yyyy}";

现在我不确定注入值的最佳方法是什么,例如,考虑到 eta 字段的格式是“硬编码”到模板中的(这样我们就可以使用不同的 @987654327 @ 格式取决于语言)

一个想法是将模板加载到StringBuilder,将命名变量替换为{0}, {1}..等的集合,然后使用旧的string.Format方法,但它并不是真正可扩展的,而且很难写完所有样板。

var formatTemplate = new StringBuilder(template)
    .Replace("{orderNo}", "{0}")
    .Replace("{warehouse}", "{1}")
    .Replace("{eta","{2")
    .ToString();
return string.Format(template, orderNo, warehouse, eta)

有没有更好的方法呢?也许一种将模板读取为插值字符串的方法?该字符串是从外部源读取的,因此我不能简单地使用 $"{marker}" 机制。

【问题讨论】:

  • 为什么会很痛苦,为什么会有很多样板代码?
  • 因为他们关心从系统发送到客户端的消息是什么,并且希望能够在系统之外定义它们。有时他们想改变它们,在某些语言中,标记的顺序不同,我想处理一组数字会让人感到困惑。编写样板文件的痛苦在于,当每个模板有 20 多个标记时,必须以正确的顺序全部替换它们。
  • 另一个问题有建议试试.Aggregate():stackoverflow.com/a/36778184/1462295
  • 也可能是stackoverflow.com/a/159126/1462295中提到的Phil Haack的解决方案

标签: c# .net string-formatting string-interpolation


【解决方案1】:

请查看SmartFormat,它实际上会做你想做的事。

(你说过,你不使用索引替换人类可读的名称)

来自他们 wiki 的示例:

String.Format 按索引引用所有参数:

String.Format("{0} {1}", person.FirstName, person.LastName)

Smart.Format 更进一步,让您可以使用命名占位符:

Smart.Format("{FirstName} {LastName}", person)

其实Smart.Format支持几种表达方式:

Smart.Format("{FirstName.ToUpper} {LastName.ToLower}", person)

工作示例需要将变量打包成匿名类型:

var formatted=Smart.Format(template, new { orderNo, warehouseName, eta })

返回正确的、期望的结果,并正确替换了标记。如果没有匿名类型,它似乎不起作用。

【讨论】:

  • SmartFormat 是一个外部库,您可以在他们的 wiki 上查看示例以获取 named placeholders
  • @dsdel 确实如此,但是如果您在此处提供示例,这将使您的答案更加完整,否则它会被视为仅链接答案,并且应该是真正的评论。
  • 这行得通。我必须将变量打包成匿名类型,但到目前为止它似乎工作:var formatted=Smart.Format(template, new { orderNo, warehouseName, eta }) 返回所需的格式化字符串。谢谢
  • 我明白,但在某些时候,这不再是一件微不足道的事情。当您有 2 个模板,每个模板有 3-4 个标记时 - 它是。当你有几十个模板,使用不同的语言,有几十个标记时,这可能会开始成为一个问题,手动编写所有替换,并以这种方式处理格式。我可以委托给外部库的越多,只需对结果进行单元测试,然后转移到更重要的东西上就越好。在这个前。我最终只做了一个包含所有必需字段的模型,每个模板类型,将它传递给 Smart.Format 并让它处理格式。
【解决方案2】:

如果您的框架支持,您可以使用字符串插值: 看看这个: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/interpolated-strings

然后您可以更新您的代码,例如:

 var orderNo = 1;
 var warehouse = "Trinidad";
 var template = $"Your order {orderNo} has dispatched from {warehouse}";

【讨论】:

  • 模板是从外部源读取的,所以 $"{}" 字符串插值不起作用,因为据我了解,它需要在编译期间组合,而不是在运行时组合。
  • 好的。您能否解释一下为什么它不起作用。我不清楚为什么它需要在编译期间组合。 orderNo 和 warehouse 将在运行时具有值。如果我错了,如果这是错误的方法,请纠正我
  • 模板是从 otside 源读取的。所以我从来没有var template = $"Your order {orderNo}..",而是var template=_dbProvider.LoadTemplate();。在运行时,模板变量确实具有"Your order {orderNo}.." 值,但字符串插值需要您在代码中进行分配。即使您从 DB 加载 "$\"Your order {orderNo}..",它也会被视为常规字符串,而不是插值字符串。
猜你喜欢
  • 1970-01-01
  • 2014-10-14
  • 2018-12-24
  • 1970-01-01
  • 1970-01-01
  • 2016-05-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多