代码之家  ›  专栏  ›  技术社区  ›  Adrian Godong

解析格式化字符串

  •  14
  • Adrian Godong  · 技术社区  · 17 年前

    示例场景:

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

    我试图做的是将格式化的字符串恢复到object(string)数组中。类似于(伪代码):

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

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

    6 回复  |  直到 17 年前
        1
  •  17
  •   rmtheis sillygoose    11 年前

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

    一种方法是 this blog post string[] ParseExact() ,与 DateTime.ParseExact()

    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;
            }
        }
    }
    
        2
  •  12
  •   ardila kristianp    10 年前

    您不能取消格式化,因为信息丢失了。 String.Format

    创建从继承的新类 string "{0}-{1}" 和 { "asdf", "qwer" } ToString() ,并稍微修改您的代码。

    如果变得太棘手,只需创建相同的类,但不从继承 然后再修改一下你的代码。

        3
  •  4
  •   Mehrdad Afshari    17 年前

    这在一般情况下是不可能的。某些信息将在中“丢失”(字符串边界) Format 方法。假设:

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

    你会如何“取消”它?

        4
  •  2
  •   Joel Goodwin    17 年前

    假设“-”不在原始字符串中,是否可以不使用Split?

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

        5
  •  1
  •   peterchen    17 年前

    一个简单的解决办法可能是

    • 将所有格式标记替换为(.*)
    • 在中转义所有其他特殊字符 format

        6
  •  0
  •   Mehmet Aras    17 年前

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

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

    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; 
    }