解析格式化的字符串

我正在尝试创建一个通用的格式化程序/解析器组合。

示例场景:

  • 我有一个字符串string.Format(),例如var format = "{0}-{1}"
  • 我有一个输入的对象(字符串)数组,例如var arr = new[] { "asdf", "qwer" }
  • 我使用格式字符串格式化数组,例如var res = string.Format(format, arr)

我想要做的是将格式化的字符串恢复回对象数组(字符串)。 像(伪代码)的东西:

 var arr2 = string.Unformat(format, res) // when: res = "asdf-qwer" // arr2 should be equal to arr 

有没有经验做过这样的事情? 我正在考虑使用正则表达式(修改原始格式字符串,然后将其传递给Regex.Matches以获取数组)并为格式字符串中的每个占位符运行它。 这是可行的还是还有其他更有效的解决方案?

您无法取消格式化,因为信息丢失了。 String.Format是一种“破坏性”算法,这意味着你不能(总是)回去。

创建一个inheritance自string的新类,在其中添加一个跟踪"{0}-{1}"{ "asdf", "qwer" } ,覆盖ToString() ,并修改一下你的代码。

如果它变得太棘手,只需创建相同的类,但不从stringinheritance并修改一些代码。

IMO,这是最好的方法。

虽然有关丢失信息的注释有效,但有时您只想获取具有已知格式的字符串的字符串值。

一种方法是我的朋友写的这篇博客文章 。 他实现了一个名为string[] ParseExact()的扩展方法,类似于DateTime.ParseExact() 。 数据以字符串数组的forms返回,但如果您能够使用它,则非常方便。

 public static class StringExtensions { public static string[] ParseExact( this string data, string format) { return ParseExact(data, format, false); } public static string[] ParseExact( this string data, string format, bool ignoreCase) { string[] values; if (TryParseExact(data, format, out values, ignoreCase)) return values; else throw new ArgumentException("Format not compatible with value."); } public static bool TryExtract( this string data, string format, out string[] values) { return TryParseExact(data, format, out values, false); } public static bool TryParseExact( this string data, string format, out string[] values, bool ignoreCase) { int tokenCount = 0; format = Regex.Escape(format).Replace("\\{", "{"); for (tokenCount = 0; ; tokenCount++) { string token = string.Format("{{{0}}}", tokenCount); if (!format.Contains(token)) break; format = format.Replace(token, string.Format("(?'group{0}'.*)", tokenCount)); } RegexOptions options = ignoreCase ? RegexOptions.IgnoreCase : RegexOptions.None; Match match = new Regex(format, options).Match(data); if (tokenCount != (match.Groups.Count - 1)) { values = new string[] { }; return false; } else { values = new string[tokenCount]; for (int index = 0; index < tokenCount; index++) values[index] = match.Groups[string.Format("group{0}", index)].Value; return true; } } } 

在通用案例中根本不可能。 一些信息将在Format方法中“丢失”(字符串边界)。 假设:

 String.Format("{0}-{1}", "hello-world", "stack-overflow"); 

你怎么会“取消格式化”呢?

假设“ – ”不在原始字符串中,你能不能只使用Split?

 var arr2 = formattedString.Split('-'); 

请注意,这仅适用于带有假设的演示示例。 任何反向算法都取决于所采用的格式类型; 如其他答案所述,甚至可能不可能进行逆运算。

一个简单的解决方案可能是

  • 用(。*)替换所有格式标记
  • format逃避所有其他特殊字符
  • 使正则表达式匹配非贪婪

这将解决最短可能匹配的模糊性。

(我不擅长RegEx,所以请纠正我,伙计:))

格式化后,您可以将生成的字符串和对象数组放入字典中,并将字符串作为键:

 Dictionary unFormatLookup = new Dictionary ... var arr = new string [] {"asdf", "qwer" }; var res = string.Format(format, arr); unFormatLookup.Add(res,arr); 

在Unformat方法中,您只需传递一个字符串并查找该字符串并返回使用的数组:

 string [] Unformat(string res) { string [] arr; unFormatLoopup.TryGetValue(res,out arr); //you can also check the return value of TryGetValue and throw an exception if the input string is not in. return arr; }