转义大括号{}以支持String.Format的字符串

5

我从数据库中读取字符串,这些字符串被输入到String.Format方法中。如果一个字符串有'{' '}'括号,但这些括号没有被正确地转义为String.Format(即添加另一个'{'来转义它们),那么String.Format将会抛出异常。

字符串具有任何组合的这些括号,因此本质上该方法需要遍历字符串并找出'{'是否有闭合括号以及它们是否形成了一个对于String.Format有效的占位符(例如{5}),那些不需要正确转义的占位符。

我可以编写一个方法来实现这一点,但我想知道.NET中是否内置了任何东西或者已经存在这样的工具?

以下是一个字符串示例:

Hello {0}, please refer to our user manual for more information {or contact us at: XXXX}

您可以看到,在将其输入到String.Format中时,{or contact us at: XXXX}会引发异常。


一个样例输入和输出会很好。 - paparazzo
如果您可以保证永远不需要转义 {digit},那么这个正则表达式非常简单。 - Marc
1
这些字符串是从哪里来的?限制输入(并禁止{})不是更容易吗?或者,如果有效的占位符来自于与无效占位符不同的地方,那么很容易就可以转义“无效”部分并将它们连接在一起。 - NullUserException
你的自定义处理工具是否可以使用不同的转义字符?你选择了一个已经被占用的字符。另一种选择是在存储时进行转义,并在 string.Format 完成后取消转义... var s = string.Format("Hello {0} plese {{or contact}}", ... ); - OscarRyz
你是否掌控将字符串插入数据库的代码?如果是这样,我认为最好使用双括号存储它。如果不行,那么你想对字符串 "{{"(已经加倍)做什么?保留原样还是变成 "{{{{"?对于更复杂的格式字符串,例如 "{0:d}",你有什么想法? - user743382
显示剩余2条评论
3个回答

2
这个怎么样:
string input = "Hello {0}, please refer for more information {or contact us at: XXXX}";
   Regex rgx = new Regex("(\\{(?!\\d+})[^}]+})");
string replacement = "{$1}";
string result = rgx.Replace(input, replacement);

Console.WriteLine("String {0}", result);

// Hello {0}, please refer for more information {{or contact us at: XXXX}}

假设应该不需要转义的唯一字符串格式为{\d+}

但是有两个注意点。首先,我们可能会遇到已经转义的花括号 - {{。解决方法比较简单:添加更多的环视…

Regex rgx = new Regex("(\\{(?!\\d+})(?!\\{)(?<!\\{\\{)[^}]+})");

换句话说,当尝试替换括号时,请确保它是孤立的。)

其次,格式本身可能并不那么简单 - 随着字符串中实际存在的格式复杂度增加,正则表达式的复杂度也会增加。例如,这个小家伙不会尝试修复以数字开头,一直到}符号而没有任何空格的格式字符串:

Regex rgx = new Regex("(\\{(?!\\d\\S*})(?!\\{)(?<!\\{\\{)[^}]+})");

作为一种附注,尽管我是那些喜欢有两个问题(嗯,有点)的人之一,但当我看到这个时,我确实会感到恐惧。
更新:如果您需要转义每个单独出现的 { 和 },那么您的任务实际上会更容易 - 但我想您需要进行两次操作。
Regex firstPass = new Regex("(\\{(?!\\d+[^} ]*}))");
string firstPassEscape = "{$1";
...
Regex secondPass        = new Regex("((?<!\\{\\d+[^} ]*)})");
string secondPassEscape = "$1}";

1
+1 - 虽然可能值得考虑格式字符串的可选“:SOMEFORMAT”部分;例如,字符串日期=String.Format(“ {0:dd/mm/yyyy}”); - RJ Lohan
更新了答案,提到了可能的两个故障点;它显示需要三到四次才能真正使其(再次)正确。 - raina77ow
这很好,但我需要考虑单个 '{' 或 '}' 可能出现的位置。 - Pacman
@Pacman 再次更新了答案;现在我认为 {{ 不应该被转换成 {{{{},并且这也反映在最后的代码片段中。 - raina77ow

0

你的自定义处理工具是否可以使用不同的转义字符?因为你选择的那个已经被占用了!

如果不可能的话,另一个选项是在存储时将其转义。当 string.Format 结束时,它会自动解除转义。

var s = string.Format("Hello {0} please ... {{or contact}}", customer.Name );
// Now use s as needed 
// now is: "Hello Joe please ... {or contact}"

谢谢回复,但请记住,一个字符串也可能只有一个 '{' 而不是两个,或者它们可以反向出现,就像这样 '}' '{'。 - Pacman
我仍然认为在插入时必须保护它们。 - OscarRyz

0

尝试:

myString = Regex.Replace(myString, @"\{(\D+)\}", "{{$1}}");

请提供一些详细信息,说明为什么这个正则表达式应该有效。此答案在“日志质量帖子”列表中。 - John Saunders
如果那个 {...} 字符串包含至少一个数字,这个正则表达式将失败。 - raina77ow
如果我理解问题的意思,他想要转义不属于格式规范的大括号...例如,他想要转义像{hello}这样的内容,而不是像{0} {1}等这样的内容。 - Icemanind

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接