How to Conditionally Format a String in .Net?
Asked Answered
E

7

33

I would like to do some condition formatting of strings. I know that you can do some conditional formatting of integers and floats as follows:

Int32 i = 0;
i.ToString("$#,##0.00;($#,##0.00);Zero");

The above code would result in one of three formats if the variable is positive, negative, or zero.

I would like to know if there is any way to use sections on string arguments. For a concrete, but contrived example, I would be looking to replace the "if" check in the following code:

string MyFormatString(List<String> items, List<String> values)
{
    string itemList = String.Join(", " items.ToArray());
    string valueList = String.Join(", " values.ToArray());

    string formatString;

    if (items.Count > 0)
    //this could easily be: 
    //if (!String.IsNullOrEmpty(itemList))
    {
        formatString = "Items: {0}; Values: {1}";
    }
    else
    {
        formatString = "Values: {1}";
    }

    return String.Format(formatString, itemList, valueList);
}
Evangelinaevangeline answered 30/9, 2008 at 19:6 Comment(0)
R
37

Well, you can simplify it a bit with the conditional operator:

string formatString = items.Count > 0 ? "Items: {0}; Values: {1}" : "Values: {1}";
return string.Format(formatString, itemList, valueList);

Or even include it in the same statement:

return string.Format(items.Count > 0 ? "Items: {0}; Values: {1}" : "Values: {1}",
                     itemList, valueList);

Is that what you're after? I don't think you can have a single format string which sometimes includes bits and sometimes it doesn't.

Rifle answered 30/9, 2008 at 19:10 Comment(13)
Not sure why this has been voted down, given that it certainly works... Any voters care to enlighten me? It's always nice to know why people don't like answers - it makes it easier to provide better ones in future.Rifle
Simplify? Absolutely lol. Using ternary if in this context is absolutely odd. 1. What if there's a third case? 2. What do you achieve by this approach - 2 lines shorter code?Sower
@loki2302: If there are more than two cases, I'd look at exactly what those cases were. I might use a switch statement. But I definitely view this as simpler than using if/else. If you're not terribly comfortable with the conditional operator, that's fine - but I'm clearly not alone in thinking that it simplifies the code, given that the majority of answers suggest the same thing. What makes you think it's "absolutely odd"? (It's not called "ternary if", by the way - it's the conditional operator.)Rifle
@Jon Skeet: are you of those who have 24" wide-screen displays? ;-) Regarding ternary if, read wiki: "Since this operator is often the only existing ternary operator in the language, it is sometimes simply referred to as "the ternary operator", though it is more accurately referred to as the conditional operator". Ternary if is absolutely legal and understandable.Sower
@loki2302: "the ternary operator" is bad enough in my view; "ternary if" is worse IMO. Why not just use the name it's been given in the language specification? As it happens, it work I have two rather large monitors... but I regularly code on a netbook too, and still find the conditional operator useful and more readable than an unnecessary if statement. Using a conditional gives the extra clue to the reader that all that's changing is the evaluation of a single expression.Rifle
@Jon Skeet: Would you disagree that f(x) is always better than f(g(x))?Sower
@loki2302: I'd need a more specific example - in particular, whether making f(g(x)) work requires f to be more complex. If both f(x) and f(g(x)) work for all values of x, then g must be an identity function. Assuming that's not what you're talking about, you need to clarify what you meant.Rifle
@Jon Skeet: I'm talking about func(new A(new B())), a.b.c.d.e.f() and other vs. absolutely stupid and explicit approach where each line of code is as simple as possible: b = new B(); a = new A(b); func(a); For me, it's absolutely the same as print(a ? b : c)Sower
@loki2302: So you never have more than one expression per statement, and never use the conditional operator at all? Sounds like a recipe for tedious code to me. There's a place for splitting things out (I've just answered another question along those lines, where doing too much in one expression was making it hard to diagnose a problem) but there's also a balance to be had. You must really hate LINQ, why you're positively encouraged to use composition to chain together a bunch of operations...Rifle
@Jon Skeet: don't mix DSLs and i-can-write-a-compiler-in-a-single-line. I'm a big fan of Boost Spirit (it's not .NET, though) and I spent 3 months to implement my own version, just to understand how it works. These are different things.Sower
@loki2302: So chaining properties together is a big no-no, but chaining method calls is fine? Seems odd to me. I suspect we'll have to agree to disagree - your position seems an extreme one to me. There's a balance to be had, and I've certainly never suggested that it's a great idea to do huge amounts in a single statement - but here we have three very simple expressions and a simple method call, so it seems absolutely fine to combine them via the conditional operator.Rifle
This technique works great for formatting ItemTemplate text in Web Forms conditionally. Never thought of placing the ? operator inside a String.Format function before.Thaxter
This is fine practice. The only annoying gotcha is that syntax highlighting wont work, at least on Visual Studio 2013.Lavender
D
6

Not within String.Format(), but you could use C#'s inline operators, such as:

return items.Count > 0 
       ? String.Format("Items: {0}; Values: {1}", itemList, valueList)
       : String.Format("Values: {0}", valueList);           

This would help tidy-up the code.

Disaccharide answered 30/9, 2008 at 19:10 Comment(0)
L
5

While not addressing the OP directly, this does fall under the question title as well.

I frequently need to format strings with some custom unit, but in cases where I don't have data, I don't want to output anything at all. I use this with various nullable types:

/// <summary>
/// Like String.Format, but if any parameter is null, the nullOutput string is returned.
/// </summary>
public static string StringFormatNull(string format, string nullOutput, params object[] args)
{
    return args.Any(o => o == null) ? nullOutput : String.Format(format, args);
}

For example, if I am formatting temperatures like "20°C", but encounter a null value, it will print an alternate string instead of "°C".

double? temp1 = 20.0;
double? temp2 = null;

string out1 = StringFormatNull("{0}°C", "N/A", temp1); // "20°C"
string out2 = StringFormatNull("{0}°C", "N/A", temp2); // "N/A"
Lenard answered 15/12, 2011 at 21:26 Comment(0)
E
2
string.Format(  (items.Count > 0 ? "Items: {0}; " : "") + "Values {1}"
              , itemList
              , valueList); 
Emporium answered 30/9, 2008 at 19:51 Comment(2)
Could you point me to the documentation that specifies the bit about starting at 0 and having no missing numbers?Evangelinaevangeline
I was mistaken--I was confusing it with the requirement that all placeholder numbers are less than the length of the argument list. Null arguments are okay as they are turned into empty strings.Emporium
S
1

Just don't. I have no idea what are both the items and values in your code, but I believe, this pair could be treated as an entity of some kind. Define this entity as a class and override its ToString() method to return whatever you want. There's absolutely nothing wrong with having if for deciding how to format this string depending on some context.

Sower answered 10/8, 2011 at 16:45 Comment(0)
I
0

This is probably not what you're looking for, but how about...

formatString = (items.Count > 0) ? "Items: {0}; Values: {1}" : "Values: {1}";
Iridotomy answered 30/9, 2008 at 19:9 Comment(0)
V
0

I hoped this could do it:

return String.Format(items.ToString(itemList + " ;;") + "Values: {0}", valueList);

Unfortunately, it seems that the .ToString() method doesn't like the blank negative and zero options or not having a # or 0 anywhere. I'll leave it up here in case it points someone else to a better answer.

Vanessa answered 30/9, 2008 at 19:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.