views:

1120

answers:

8

The .NET Framework gives us the Format method:

string s = string.Format("This {0} very {1}.", "is", "funny");
// s is now: "This is very funny."

I would like an "Unformat" function, something like:

object[] params = string.Unformat("This {0} very {1}.", "This is very funny.");
// params is now: ["is", "funny"]

I know something similar exists in the ANSI-C library (printf vs scanf).

The question: is there something similiar in C#?

Update: Capturing groups with regular expressions are not the solution I need. They are also one way. I'm looking for a system that can work both ways in a single format. It's OK to give up some functionality (like types and formatting info).

+2  A: 

You could do string[] parts = string.Split(' '), and then extract by the index position parts[1] and parts [3] in your example.

endian
This works, but only for this string, as the {} values don't have spaces in them. Otherwise the indexes would be off.
pezi_pink_squirrel
A: 

You'll need to write a regular expression to get this type of functionality.

Sean
+2  A: 

Regex with grouping?

/This (.*?) very (.*?)./
annakata
+8  A: 

There's no such method, probably because of problems resolving ambiguities:

string.Unformat("This {0} very {1}.", "This is very very funny.")
// are the parameters equal to "is" and "very funny", or "is very" and "funny"?

Regular expression capturing groups are made for this problem; you may want to look into them.

mquander
+1  A: 

Yep. These are called "regular expressions". The one that will do the thing is

This (?<M0>.+) very (?<M1>.+)\.
Anton Gogolev
I think the whole point is to circum-vent the overly complex and cryptic syntax of RegEx and provide something lightweight and simple in the general cases where you don't need the complexity. Thus the format of string.Format is very desireable and self-describing for the general cases where you would want to pattern match.
Marchy
A: 

Using regular expressions is your best bet. Investigate the Regex class.

mhenry1384
+1  A: 

@mquander: Actualy, PHP solves it even different:

$s = "This is very very funny.";
$fmt = "This %s very %s.";
sscanf($s, $fmt, $one, $two);
echo "<div>one: [$one], two: [$two]</div>\n";
//echo's: "one: [is], two: [very]"

But maybe your regular expression remark can help me. I just need to rewrite "This {0} very {1}." to something like: new Regex(@"^This (.*) very (.*)\.$"). This should be done programmatical, so I can use one format string on the public class interface.

BTW: I've already have a parser to find the parameters: see the Named Format Redux blog entry by Phil Haack (and yes, I also want named paramters to work both ways).

doekman
+1  A: 

I came across the same problem, i belive that there is a elegante solution using REGEX... but a came up with function in C# to "UnFormat" that works quite well. Sorry about the lack of comments.

    /// <summary>
    /// Unformats a string using the original formating string. 
    /// 
    /// Tested Situations:
    ///    UnFormat("<nobr alt=\"1\">1<nobr>", "<nobr alt=\"{0}\">{0}<nobr>") : "1"
    ///    UnFormat("<b>2</b>", "<b>{0}</b>") : "2"
    ///    UnFormat("3<br/>", "{0}<br/>") : "3"
    ///    UnFormat("<br/>4", "<br/>{0}") : "4"
    ///    UnFormat("5", "") : "5"
    ///    UnFormat("<nobr>6<nobr>", "<nobr>{0}<nobr>") : "6"
    ///    UnFormat("<nobr>2009-10-02<nobr>", "<nobr>{0:yyyy-MM-dd}<nobr>") : "2009-10-02"
    ///    UnFormat("<nobr><nobr>", "<nobr>{0}<nobr>") : ""
    ///    UnFormat("bla", "<nobr>{0}<nobr>") : "bla"
    /// </summary>
    /// <param name="original"></param>
    /// <param name="formatString"></param>
    /// <returns>If an "unformat" is not possible the original string is returned.</returns>
    private Dictionary<int,string> UnFormat(string original, string formatString)
    {
       Dictionary<int, string> returnList = new Dictionary<int, string>();

       try{
          int index = -1;

          // Decomposes Format String
          List<string> formatDecomposed = new List<string> (formatString.Split('{'));
          for(int i = formatDecomposed.Count - 1; i >= 0; i--)
          {
             index = formatDecomposed[i].IndexOf('}') + 1;

             if (index > 0 && (formatDecomposed[i].Length - index) > 0)
             {
                formatDecomposed.Insert(i + 1, formatDecomposed[i].Substring(index, formatDecomposed[i].Length - index));
                formatDecomposed[i] = formatDecomposed[i].Substring(0, index);
             }
             else
                //Finished
                break;
          }

          // Finds and indexes format parameters
          index = 0;
          for (int i = 0; i < formatDecomposed.Count; i++)
          {
             if (formatDecomposed[i].IndexOf('}') < 0)
             {
                index += formatDecomposed[i].Length;
             }
             else
             {
                // Parameter Index
                int parameterIndex;
                if (formatDecomposed[i].IndexOf(':')< 0)
                   parameterIndex = Convert.ToInt16(formatDecomposed[i].Substring(0, formatDecomposed[i].IndexOf('}')));
                else
                   parameterIndex = Convert.ToInt16(formatDecomposed[i].Substring(0, formatDecomposed[i].IndexOf(':')));

                // Parameter Value
                if (returnList.ContainsKey(parameterIndex) == false)
                {
                   string parameterValue;

                   if (formatDecomposed.Count > i + 1)
                      if (original.Length > index)
                         parameterValue = original.Substring(index, original.IndexOf(formatDecomposed[i + 1], index) - index);
                      else
                         // Original String not valid
                         break;
                else
                   parameterValue = original.Substring(index, original.Length - index);

                returnList.Add(parameterIndex, parameterValue);
                index += parameterValue.Length;
             }
             else
                index += returnList[parameterIndex].Length;

             }
          }

          // Fail Safe #1
          if (returnList.Count == 0) returnList.Add(0, original);
       } 
       catch
       {
          // Fail Safe #2
          returnList = new Dictionary<int, string>();
          returnList.Add(0, original);
       }

       return returnList;
    }
Nuno Rodrigues