String Format descriptive text - c#

Is it possible to add some descriptive text to a string format specifier?
Example:
string.Format ("{0:ForeName} is not at home", person.ForeName);
In the example ForeName is added as description.
The above syntax is obviously incorrect, but just to show the idea.
The reason I am asking, is because in my case the strings are in a resource file, so in the resource file you currently only see
{0} is not at home
in some cases it is hard to grasp what the context of {0} is.
EDIT:
In c# 6 string interpolation with the $ operator has been introduced, so string.Format is not needed anymore:
$"{person.ForeName} is not at home";

We usually put comments into our resources file e.g. {0} = Forename.
Then anybody who might be translating the string knows what {0} represents and can translate accordingly.
Also if you use ReSharper, you can enter the comment at the same time when you are adding your string to resources.

Phil Haack and Peli have written a couple of interesting blog posts about alternatives to the default string.format function. They might interest you.
Basically they allow you to use object properties inside the format string like this:
string s = NamedFormat("Hello {FullName} ({EmailAdrress})!", person);
You can the related blog posts here:
http://blog.dotnetwiki.org/2009/01/16/NamedFormatsPexTestimonium.aspx
http://haacked.com/archive/2009/01/14/named-formats-redux.aspx/
http://haacked.com/archive/2009/01/04/fun-with-named-formats-string-parsing-and-edge-cases.aspx/
Perhaps one of the solutions covered in those blog posts would suit your needs.

For strings your method should work, since strings will ignore any format specifiers. However you run the risk of accidentally using that for non-string types, in which case the string will either be translated as format codes or literally displayed:
string.Format ("{0:ForeName} is not at home", "Johnny");
//"Johnny is not at home"
string.Format ("{0:ForeName} will be home at {1:HomeTime}", "Johnny", DateTime.Today)
//Johnny will be home at 0o0eTi0e -- H, h, and m are DateTime format codes.
However since you're storing these in a resource file, I would instead use the "comment" field in the resource file - you could store a copy of the format string and add your descriptions there.

There is no built-in C# function for that. The best I can propose is to insert a comment (this will have no performance impact) :
string.Format ("{0"/*ForeName*/+"} is not at home", person.ForeName);
Personnaly, I don't find it readable, the best approch is to use a third-party tool as David Khaykin suggested in comment (see this answer)

IDEOne.com demo
Here is a somewhat naive implementation of StackOverflow's formatUnicorn method:
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Reflection;
public class Test
{
public static void Main()
{
string formatString = "{firstName} {lastName} is awesome.";
Console.WriteLine(formatString.FormatUnicorn(new {
firstName = "joe",
lastName = "blow"
}));
}
}
public static class StringExtensions {
public static string FormatUnicorn(this string str, object arguments) {
string output = str;
Type type = arguments.GetType();
foreach (PropertyInfo property in type.GetProperties())
{
Regex regex = new Regex(#"\{" + property.Name + #"\}");
output = regex.Replace(output, property.GetValue(arguments, null).ToString());
}
return output;
}
}
The biggest drawback here is the use of reflection, which can be slow. The other is that it doesn't allow for format specifiers.
A better approach might be to create a more complex regular expression that just strips out the comments.

string.Format ("{0} is not at home {1} ", person.ForeName, person.Something);
This shall print the ForeName instead of {0} and something in {1}. There is no way to as you said.

As of Visual Studio 2015 you can do this with Interpolated Strings (its a compiler trick, so it doesn't matter which version of the .net framework you target).
The code then looks something like this
string txt = $"{person.ForeName} is not at home {person.Something}";
Its not ideal if you want to put the strings into resource files for translation, but it oftern makes the code more readable and less error prone.

Related

Get a part of that String C#

:barbosza!barbosza#barbosza.tmi.twitch.tv PRIVMSG #pggamesbr :My text
I want the part after the second ':', but i can't split by ':' because sometimes contains it too.
You can split and specify the maximum number of items, so that everything after the second colon ends up in the third item:
string[] parts = str.Split(new char[]{':'}, 3);
The part after the second colon is now in parts[2].
I guess that "he contains it too" means "My text contains it too".
In that case, do this
string toFind = "#pggamesbr :";
string myText = myString.Substring(myString.IndexOf(toFind) + toFind.Length);
I like Guffa's simple Split solution, and would go with that if this is all you need here. But, just for fun...
If you run into a lot of odd cases like this -- things you wish were easier to do with strings -- you can consider adding extension methods to handle them. E.g.,
using System;
public static MyStringExtentions
{
public static string After(this string orig, char delimiter)
{
int p = orig.indexOf(delimiter);
if (p == -1)
return string.Empty;
else
return orig.Substring(p + 1);
}
}
And then, in your existing code, as long as you have a using directive to include reference access to MyStringExtentions's definition:
string afterPart = myString.After(':').After(':');
Disclaimer: I didn't actually test this. Some tuning may be required. And it could probably be tuned to be more efficient, etc.
Again, this is probably overkill for this one problem. (See Guffa's perfectly good simple answer for that.) Just tossing it out for when you find yourself with lots of these and want a common way to make them available.
Ref. Extension Methods (C# Programming Guide)

Trimming strings between two points

I have a string as follows:
ListViewSubItem: {Debian6/Debian6.vmx }
What would be the most efficient way of getting the following output:
Debian6/Debian6.vmx
int beginidx = haystack.IndexOf('{');
string needle = haystack.SubString(beginidx,
haystack.IndexOf('}') - beginidx + 1).Trim();
string result = Regex.Match("ListViewSubItem: {Debian6/Debian6.vmx }", #"(?<={)(.+?)(?=})").Value;
You can use a regex:
\{\s*(.*)\s*\}
The desired string will be in the first captured group (Match.Groups[1]).
Example:
string output = Regex.Match(input, #"\{\s*(.*?)\s*\}").Groups[1].Value;
As was pointed out, regexes are slower than plain string manipulation. If performance is an issue, and the string extraction is in a tight loop, then it may be better to use an optimized method. Otherwise, regex vs string is IMHO a matter of personal preference.
I'm going to guess you didn't generate that string yourself. So the question is, why parse it? This looks like the sort of question where you should take a step back and think of what you're trying to solve, and if another method might be cleaner.
I am not familiar with the ListViewSubItem class, but it seems like you have one of these and you have called ToString() on it. Now you are parsing the output of ToString() to see the model object your sub-item represents.
Does this not seem backwards to you? Maybe you should deal with the ListViewSubItem object itself (from a brief look at the documentation, what you want seems to be the Text property), rather than fiddling with what ToString() returns, which seems volatile and dependent on the implementation of that class's ToString() method (which, though likely not, could theoretically change from release to release). Not to mention corner cases like "what if the string contains the } character?"
For this in other reasons, as a general rule I think you should not have to deal with serialization when your data source is in memory the whole time.
So, in summary, if you have something like this:
ListViewSubItem item = /* ... */;
string s = item.ToString();
// TODO: parse {Debian} out of ListViewSubItem {Debian}
Why not this instead:
ListViewSubItem item = /* ... */;
string OS = item.Text;

how to get a String with String.Format to execute?

I have a little chunk of code (see below) that is returning the string:
string.Format("{0}----{1}",3,"test 2");
so how do I get this to actually "Execute"? To run and do the format/replacement of {0} and {1}?
My Code snippet:
StringBuilder sb = new StringBuilder();
sb.Append("{0}----{1}\",");
sb.AppendFormat(ReturnParamValue(siDTO, "siDTO.SuggestionItemID,siDTO.Title"));
string sbStr = "=string.Format(\""+sb.ToString()+");";
yes, ReturnParamValue gives the actually value of the DTO.
Anyways, I've taken a look at the following (but it doesn't say how to execute it:
How to get String.Format not to parse {0}
Maybe, I just should put my code snippet in a method. But, what then?
Why are you including String.Format in the string itself?
If you're looking for a generic "let me evaluate this arbitrary expression I've built up in a string" then there isn't a simple answer.
If, instead, you're looking at how to provide the parameters to the string from a function call, then you've got yourself all twisted up and working too hard.
Try something like this, based on your original code:
string result
= string.Format(
"{0}----{1}",
ReturnParamValue(siDTO, "siDTO.SuggestionItemID,siDTO.Title"));
Though, this won't entirely work since your original code seems to be only providing a single value, and you have two values in your format string - the {0} will be replaced with the value from your function, and {1} left unchanged.
What output are you expecting?
Does your ReturnParamValue() function try to return both the label and the value in a single string? If it does, and if they're comma separated, then you could try this:
var value = ReturnParamValue(siDTO, "siDTO.SuggestionItemID,siDTO.Title"));
var pieces = string.Split(',');
string result
= string.Format( "{0}----{1}", pieces[0], pieces[1]);
Though this is seriously working too hard if ReturnParamValue() is a method you control.
Update Fri 6 August
Check out the declaration for string.Format() as shown on MSDN:
public static string Format(
string format,
params Object[] args
)
Unlike the special casing you might have seen in C for printf(), there's nothing special or unusual about the way string.Format() handles multiple parameters. The key is the params keyword, which asks the compiler to provide a little "syntactic sugar" where it combines the parameters into an array for you.
Key here is that the wrapping doesn't happen if you're already passing a single object[] - so if you wanted to, you could do something like this:
object[] parameters
= ReturnParamValues(siDTO, "siDTO.SuggestionItemID,siDTO.Title");
string result
= string.Format("{0}----{1}----{2}", parameters);
Though, if I saw something like this in any codebase I maintained, I'd be treating it as a code-smell and looking for a better way to solve the problem.
Just because it's possible doesn't mean it's advisable. YMMV, of course.
I don't think you can execute it. Java is not really a interpreted language.
You may make use of scripting languages (which can even embed in your Java app as I know, start from JDK6) for such purpose, like Groovy
You could use RegEx to parse the three parameters out of the string, and then pass them to a real, actual string.Format method :-)
It looks like what you want is something like this:
string sbStr = string.Format("{0}----{1}", siDTO.SuggestionItemID, siDTO.Title);
Maybe i didn't understand your question completely, but it sounds like you need to format a format-string. If that's true you could maybe try something like this:
int width = 5;
string format = String.Format("{{0,{0}}}----{{1,{0}}}", width);
string result = String.Format(format, "ab", "cd");
So the trick is simply to escape the { or } by using a double {{ or }}.

Reverse of String.Format? [duplicate]

This question already has answers here:
Closed 13 years ago.
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.
Here is some code from someone attempting a Scanf equivalent in C#:
http://www.codeproject.com/KB/recipes/csscanf.aspx
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
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.

C# How to add placement variable into a resource string

This should be easy, but can't find anything to explain it.
Say I am writing something out on console.writeln like:
console.writeln("Jim is a {0} ", xmlscript);
Say I wanted to convert string `"Jim is.." to a resource string in a global resource.resx. It would be:
jimstring jim is a {0}
and I would refer to it in code as
console.writeln(Resources.jimstring)
How to I put the placement variable (xmlscript) (is this what they are called?) into the resource string in console.writeln?
Thanks,
Bob
As Jeff Johnson mentioned in his answer, it basically the exact same thing as the original Console.WriteLine(). The resource string is just a string. So you reference the resource file and do the format.
If you need it for something other than the Console you can use the String.Format():
var newString = String.Format(resources.jimstring, xmlscript);
Console.WriteLine(Resources.jimstring, xmlscript);
Console.WriteLine takes additional formatting arguments that will replace the {0} in your Resources.jimstring string.
More info here: http://msdn.microsoft.com/en-us/library/828t9b9h.aspx

Categories

Resources