14

Possible Duplicate:
Parsing formatted string.

How can I use a String.Format format and transform its output to its inputs?

For example:

string formatString = "My name is {0}.  I have {1} cow(s).";

string s = String.Format(formatString, "strager", 2);

// Call the magic method...
ICollection<string> parts = String.ReverseFormat(formatString, s);
// parts now contains "strager" and "2".

I know I can use regular expressions to do this, but I would like to use the same format string so I only need to maintain one line of code instead of two.

Community
  • 1
  • 1
strager
  • 88,763
  • 26
  • 134
  • 176
  • Dupe: http://stackoverflow.com/questions/1410012/parsing-formatted-string – Mehrdad Afshari Oct 02 '09 at 21:01
  • My bad; I didn't know it was a dupe. Thanks Mehrdad, I'm voting to close now. – John Rudy Oct 02 '09 at 21:05
  • It is a dupe, but my question wasn't answered there. – strager Oct 02 '09 at 21:10
  • 1
    strager: That's because there is no in-box answer for this. :) No matter what you're in a mode of either kludging something together (a la my answer) or building a whole new custom class to provide both sides of the functionality. – John Rudy Oct 02 '09 at 21:17
  • 1
    Your question is answered. There's no algorithm that can do it in the generic case. Think of it as 2 + 2 = 4. If they give you 4 and +, how can you deduce whether the input operands were 2 and 2 or 1 and 3? You can't. – Mehrdad Afshari Oct 02 '09 at 21:23
  • @Mehrdad, That's a poor example, IMO. I can easily do this using regular expressions. I'm wondering if there's a possible way to do it without maintaining two parts (the format and the regexp). – strager Oct 02 '09 at 22:17
  • @stager: It's a regular expression you craft for your specific case. It's not possible to do it in general case *in theory*: You can unambiguously parse an ambiguous production in a grammar. You can always convert a syntax tree to a grammar production but the reverse is not true if the grammar is ambiguous, that is, there is more than one way to generate the same word. – Mehrdad Afshari Oct 02 '09 at 22:28
  • No idea how this not answered all these years. Maybe it dint exist back then. Anyways it is done like this string formatString = "My name is %s. I have %d cow(s)."; You use %s for strings and %d for int – Neville Nazerane Oct 11 '15 at 04:41
  • You can achieve this quite easily using two Regex capturing groups: https://stackoverflow.com/questions/906493/how-do-i-access-named-capturing-groups-in-a-net-regex – Alexandru Feb 19 '21 at 18:32

3 Answers3

1

You'll have to implement it yourself, as there's nothing built in to do it for you.

To that end, I suggest you get the actual source code for the .Net string.format implmentation (actually, the relevant code is in StringBuilder.AppendFormat()). It's freely available, and it uses a state machine to walk the string in a very performant manner. You can mimic that code to also walk your formatted string and extract that data.

Note that it won't always be possible to go backwards. Sometimes the formatted string can have characters the match the format specifiers, making it difficult to impossible for the program to know what the original looked like. As I think about it, you might have better luck walking the original string to turn it into a regular expression, and then use that to do the match.

I'd also recommend renaming your method to InvertFormat(), because ReverseFormat sounds like you'd expect this output:

.)s(woc 2 evah .regarts si eman yM

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
1

Here is some code from someone attempting a Scanf equivalent in C#:

http://www.codeproject.com/KB/recipes/csscanf.aspx

BobbyShaftoe
  • 28,337
  • 7
  • 52
  • 74
-1

I don't believe there's anything in-box to support this, but in C#, you can pass an array of objects directly to any method taking params-marked array parameters, such as String.Format(). Other than that, I don't believe there's some way for C# & the .NET Framework to know that string X was built from magic format string Y and undo the merge.

Therefore, the only thing I can think of is that you could format your code thusly:

object[] parts = {"strager", 2};
string s = String.Format(formatString, parts);

// Later on use parts, converting each member .ToString()
foreach (object p in parts)
{
    Console.WriteLine(p.ToString());
}

Not ideal, and probably not quite what you're looking for, but I think it's the only way.

John Rudy
  • 37,282
  • 14
  • 64
  • 100