C# 中的命名字符串格式
在 C# 中,有没有办法按名称而不是位置来格式化字符串?
在Python中,我可以做类似这个例子的事情(从这里无耻地窃取):
>>> print '%(language)s has %(#)03d quote types.' % \
{'language': "Python", "#": 2}
Python has 002 quote types.
在 C# 中有什么办法可以做到这一点吗? 举例来说:
String.Format("{some_variable}: {some_other_variable}", ...);
能够使用变量名来做到这一点会很好,但是字典也是可以接受的。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(18)
没有内置的方法来处理这个问题。
这是一种方法
这是另一个
A第三种改进方法部分基于上述两种方法,来自 Phil Haack
更新: 该方法现已从 C# 6(2015 年发布)中内置。
字符串插值
There is no built-in method for handling this.
Here's one method
Here's another
A third improved method partially based on the two above, from Phil Haack
Update: This is now built-in as of C# 6 (released in 2015).
String Interpolation
我刚刚在我的博客上发布了一个实现: http://haacked.com/archive/2009/01/04/fun-with-named-formats-string-parsing-and-edge-cases.aspx
它地址这些其他实现在大括号转义方面存在一些问题。 帖子有详细信息。 它也执行 DataBinder.Eval 的操作,但仍然非常快。
I have an implementation I just posted to my blog here: http://haacked.com/archive/2009/01/04/fun-with-named-formats-string-parsing-and-edge-cases.aspx
It addresses some issues that these other implementations have with brace escaping. The post has details. It does the DataBinder.Eval thing too, but is still very fast.
内插字符串已添加到 C# 6.0 和 Visual Basic 14 中,
两者都是通过新的 Roslyn 引入的Visual Studio 2015 中的编译器。
C# 6.0:
返回“\{someVariable} 以及 \{someOtherVariable}”
或返回 $"{someVariable} 以及 {someOtherVariable}"
来源:C#6.0 中的新增功能
VB 14:
返回 $"{someVariable} 以及 {someOtherVariable}"
值得注意的功能(在 Visual Studio 2015 IDE 中):
{index }
有效,但也可以{(index + 1).ToString().Trim()}
尽情享受! (&点击VS中的“发送微笑”)
Interpolated strings were added into C# 6.0 and Visual Basic 14
Both were introduced through new Roslyn compiler in Visual Studio 2015.
C# 6.0:
return "\{someVariable} and also \{someOtherVariable}"
ORreturn $"{someVariable} and also {someOtherVariable}"
source: what's new in C#6.0
VB 14:
return $"{someVariable} and also {someOtherVariable}"
Noteworthy features (in Visual Studio 2015 IDE):
{index}
works, but also{(index + 1).ToString().Trim()}
Enjoy! (& click "Send a Smile" in the VS)
您还可以使用这样的匿名类型:
当然,如果您还想解析格式,则需要更多代码,但是您可以使用此函数格式化字符串,例如:
You can also use anonymous types like this:
Of course it would require more code if you also want to parse formatting, but you can format a string using this function like:
似乎没有办法开箱即用地做到这一点。 不过,实现您自己的
IFormatProvider
看起来是可行的 链接到值的IDictionary
。输出:
需要注意的是,您不能混合使用
FormatProviders
,因此不能同时使用精美的文本格式。There doesn't appear to be a way to do this out of the box. Though, it looks feasible to implement your own
IFormatProvider
that links to anIDictionary
for values.Outputs:
The caveat is that you can't mix
FormatProviders
, so the fancy text formatting can't be used at the same time.框架本身没有提供执行此操作的方法,但您可以查看这篇文章 作者:斯科特·汉塞尔曼。 用法示例:
James Newton-King 的这段代码 类似,并且使用子属性和索引,
James 的代码依赖 System.Web.UI.DataBinder 来解析字符串并需要引用 System.Web ,有些人不喜欢在非 Web 应用程序中这样做。
编辑:哦,如果您没有准备好属性的对象,它们可以很好地与匿名类型配合使用:
The framework itself does not provide a way to do this, but you can take a look at this post by Scott Hanselman. Example usage:
This code by James Newton-King is similar and works with sub-properties and indexes,
James's code relies on System.Web.UI.DataBinder to parse the string and requires referencing System.Web, which some people don't like to do in non-web applications.
EDIT: Oh and they work nicely with anonymous types, if you don't have an object with properties ready for it:
请参阅 https://stackoverflow.com/questions/271398?page=2#358259
使用链接-对于扩展,你可以这样写:
你会得到
“foo 2 System.Object
”。See https://stackoverflow.com/questions/271398?page=2#358259
With the linked-to extension you can write this:
and you'll get
"foo 2 System.Object
".我认为您将获得的最接近的是索引格式:
还有 String.Replace(),如果您愿意分多个步骤执行此操作并相信您不会在其他任何地方找到您的“变量”字符串:
扩展它以使用列表:
您可以使用字典来做到这一点 也通过迭代它的 .Keys 集合,但是通过使用 List>> 我们可以利用 List 的 .ForEach() 方法并将其压缩回一行:
lambda 会更简单,但我仍然使用 .Net 2.0。 另请注意,迭代使用时 .Replace() 性能并不出色,因为 .Net 中的字符串是不可变的。 另外,这需要以委托可以访问的方式定义
MyString
变量,因此它还不完美。I think the closest you'll get is an indexed format:
There's also String.Replace(), if you're willing to do it in multiple steps and take it on faith that you won't find your 'variables' anywhere else in the string:
Expanding this to use a List:
You could do that with a Dictionary<string, string> too by iterating it's .Keys collections, but by using a List<KeyValuePair<string, string>> we can take advantage of the List's .ForEach() method and condense it back to a one-liner:
A lambda would be even simpler, but I'm still on .Net 2.0. Also note that the .Replace() performance isn't stellar when used iteratively, since strings in .Net are immutable. Also, this requires the
MyString
variable be defined in such a way that it's accessible to the delegate, so it's not perfect yet.我的开源库 Regextra 支持命名格式(除其他外)。 它当前面向 .NET 4.0+,可在 NuGet 上获取。 我还有一篇关于它的介绍性博客文章:Regextra:帮助您减少(问题){2}。
命名格式位支持:
示例:
结果:
查看该项目的 GitHub 链接(上面)和 wiki 以获取其他示例。
My open source library, Regextra, supports named formatting (amongst other things). It currently targets .NET 4.0+ and is available on NuGet. I also have an introductory blog post about it: Regextra: helping you reduce your (problems){2}.
The named formatting bit supports:
Example:
Result:
Check out the project's GitHub link (above) and wiki for other examples.
示例:
输出:
你好,wayjet,今天是2011-05-04,这是你第18次登录,积分{ 100.40 }
Example:
Output:
你好,wayjet,今天是2011-05-04, 这是你第18次登录,积分{ 100.40 }
检查这个:
示例:
与其他解决方案相比,性能相当不错。
Check this one:
Sample:
Performance is pretty ok compared to other solutions.
我怀疑这是否可能。 首先想到的是如何访问局部变量名称?
然而,可能有一些巧妙的方法使用 LINQ 和 Lambda 表达式来做到这一点。
I doubt this will be possible. The first thing that comes to mind is how are you going to get access to local variable names?
There might be some clever way using LINQ and Lambda expressions to do this however.
这是我不久前做的一个。 它使用带有单个参数的 Format 方法扩展 String。 好处是,如果您提供像 int 这样的简单参数,它将使用标准 string.Format,但如果您使用像匿名类型这样的东西,它也可以工作。
用法示例:
将导致“史密斯家族有 4 个孩子”。
它不会执行诸如数组和索引器之类的疯狂绑定操作。 但它超级简单且高性能。
Here's one I made a while back. It extends String with a Format method taking a single argument. The nice thing is that it'll use the standard string.Format if you provide a simple argument like an int, but if you use something like anonymous type it'll work too.
Example usage:
Would result in "The Smith family has 4 children."
It doesn't do crazy binding stuff like arrays and indexers. But it is super simple and high performance.
这是适用于任何对象的简单方法:
这里是如何使用它:
输出:2012 年 2 月 27 日
here is a simple method for any object:
And here how to use it:
output : 2/27/2012
尽管接受的答案提供了一些很好的例子,但 .Inject 以及一些 Haack 示例不处理转义。 许多人还严重依赖 Regex(速度较慢)或 DataBinder.Eval,这些在 .NET Core 和其他一些环境中不可用。
考虑到这一点,我编写了一个基于状态机的简单解析器,它通过字符流式传输,逐个字符写入
StringBuilder
输出。 它被实现为String
扩展方法,并且可以采用带有参数的Dictionary
或object
作为输入(使用反射)。它处理无限级别的
{{{escaping}}}
并在输入包含不平衡的大括号和/或其他错误时抛出FormatException
。最终,所有逻辑都归结为 10 个主要状态 - 当状态机位于括号外部且同样位于括号内部时,下一个字符要么是开大括号、转义开大括号、闭大括号、转义闭大括号,或者一个普通的角色。 随着循环的进行,每个条件都会被单独处理,将字符添加到输出
StringBuffer
或键StringBuffer
中。 当参数关闭时,StringBuffer
键的值用于在字典中查找参数的值,然后将其推入输出StringBuffer
中。 最后,返回输出StringBuffer
的值。Even though the accepted answer gives some good examples, the .Inject as well as some of the Haack examples do not handle escaping. Many also rely heavily on Regex (slower), or DataBinder.Eval which is not available on .NET Core, and in some other environments.
With that in mind, I've written a simple state machine based parser that streams through characters, writing to a
StringBuilder
output, character by character. It is implemented asString
extension method(s) and can take both aDictionary<string, object>
orobject
with parameters as input (using reflection).It handles unlimited levels of
{{{escaping}}}
and throwsFormatException
when input contains unbalanced braces and/or other errors.Ultimately, all the logic boils down into 10 main states - For when the state machine is outside a bracket and likewise inside a bracket, the next character is either an open brace, an escaped open brace, a closed brace, an escaped closed brace, or an ordinary character. Each of these conditions is handled individually as the loop progresses, adding characters to either an output
StringBuffer
or a keyStringBuffer
. When a parameter is closed, the value of the keyStringBuffer
is used to look up the parameter's value in the dictionary, which then gets pushed into the outputStringBuffer
. At the end, the value of the outputStringBuffer
is returned.我实现的这是一个简单的类,它复制了 String.Format 的功能(使用类时除外)。 您可以使用字典或类型来定义字段。
https://github.com/SergueiFedorov/NamedFormatString
C# 6.0 将此功能直接添加到语言规范中,所以
NamedFormatString
是为了向后兼容。I implemented this is a simple class that duplicates the functionality of String.Format (except for when using classes). You can either use a dictionary or a type to define fields.
https://github.com/SergueiFedorov/NamedFormatString
C# 6.0 is adding this functionality right into the language spec, so
NamedFormatString
is for backwards compatibility.我以与现有解决方案略有不同的方式解决了这个问题。
它执行命名项替换的核心(而不是某些人所做的反射位)。 它非常快速且简单......
这是我的解决方案:
它的使用方式如下:
希望有人发现这很有用!
I solved this in a slightly different way to the existing solutions.
It does the core of the named item replacement (not the reflection bit that some have done). It is extremely fast and simple...
This is my solution:
It is used in the following way:
Hope someone finds this useful!
编辑:
我应该说的是,“不,我不相信 C# 支持您想要做的事情。这已经是您所能达到的最接近的结果了。”
Edit:
What I should have said was, "No, I don't believe what you want to do is supported by C#. This is as close as you are going to get."