String.Format: Input string was not in a correct format [closed]
Asked Answered
S

5

40

The following code keep giving me error saying Input string was not in a correct format, but I am pretty sure it is right, isn't it?

int id = 112;

String[] newData = { "1", "2", "21", "reidb", "reidb", "reidb", "reidb", "aa", 
                      "Some description", "11", "2012-02-28", "2012-01-29", "true", "1", "1", 
                      "true", "note note note", "true", "1", "2011-12-03", "45"};

String data = "{ cmd: \"save magellan deal\", data: { id: {0} , AId: {1}, " +
            "CId: {2}, CCId:{3}, LA: \"{4}\", BA: \"{5}\" , " +
            "LSA: \"{6}\" , BSA: \"{7}\" , \"path: \"{8}\"," +
            "dscp: \"{9}\", SI: \"{10}\", CD: \"{11}\", " +
            "period: \"{12}\", IsStatic: {13}, LSD: {14}, LC: {15}, RB: {16},} " +
            "Notes: \"{17}\", IsEE: {18}, RBy: {19}, DPDD: \"{20}\", LId: {21} } }";


String cmd = String.Format(data, id.toString(), newData);

Anyone any ideas?

=== EDIT ===

after fixing the braces, a new error of "Index (zero based) must be greater than or equal to zero and less than the size of the argument list." is given. the newData has 21 and plus the id.toString(), should be exact 22?

Swarth answered 29/1, 2013 at 0:19 Comment(9)
You need to escape curly braces. Use two for json data '{{'.Folkmoot
what is your format..? look up on how to use string.FormatArluene
personally, I wouldn't use string.Format for this at all - it's just adding complexity for no good reason. There's no way you can quickly tell which argument goes to which placeholder. string concatenation has the same semantics, no escaping rules to remember, and it's even slightly faster - and then you can actually see the context of the variables you're inserting, which I assume have some meaning in the real program.Thinner
@EamonNerbonne: I agree about the complexity, but disagree about speed. Strings are immutable in C#, so doing multiple string concatenations as in this case is likely to be slower. However, the performance difference is not likely to matter for most use cases so I would favor clearer, more maintainable code over String.Format.Feathered
This is pretty awful code. Have you at least considered using a real json serializer?Polley
@Eric J. string's may be immutable, but behind the scenes string.Format needs to build a new string by concatenation. Additionally, it needs to parse the format string - something that's not free; it's quite possibly the most expensive part of the entire operation. By contrast, a bunch of inline string-concatenations are optimized by the C# compiler to just one concat call, i.e. somewhat faster than string.Join or StringBuilder. So there's no technical reason to avoid it; and your code will be much more readable for it.Thinner
@HansPassant: I didn't even see the resemblance to JSON at first! You're right he should just use Json.NET if he's trying to make a javascript literal. He's not making (valid) JSON anyhow, since the key names aren't quoted, and modern browsers will choke on that (so it's probably a js literal).Thinner
@EamonNerbonne: String.Format uses StringBuilder.AppendFormat internally reflector.webtropy.com/default.aspx/4@0/4@0/DEVDIV_TFS/Dev10/… which allocates a buffer and populates the buffer. It does not do string concatenation for each argument. reflector.webtropy.com/default.aspx/4@0/4@0/DEVDIV_TFS/Dev10/…Feathered
string building in that fashion is string concatenation. I'm sorry I wasn't clear: I didn't mean to say it uses the method string.Concat. I meant that it's formatting the string by concatenating a bunch of smaller strings. To be clear: this doesn't invalidate the unreadableness that string.Format often causes, nor the poor type checking, nor the fact that string.Format is somewhat slower. Admittedly, the performance difference isn't large enough to matter - but its certain not a reason to prefer string.Format either.Thinner
L
80

Escape the "{", "}" (by duplicating them) in the format string:

"{{ cmd: \"save magellan deal\", data: {{ id: {0} , AId: {1}, " +
"CId: {2}, CCId:{3}, LA: \"{4}\", BA: \"{5}\" , " +
"LSA: \"{6}\" , BSA: \"{7}\" , \"path: \"{8}\"," +
"dscp: \"{9}\", SI: \"{10}\", CD: \"{11}\", " +
"period: \"{12}\", IsStatic: {13}, LSD: {14}, LC: {15}, RB: {16},}} " +
"Notes: \"{17}\", IsEE: {18}, RBy: {19}, DPDD: \"{20}\", LId: {21} }} }}"

And you have 22 elements in the format string and 21 in the array.

Lansing answered 29/1, 2013 at 0:21 Comment(3)
hmm, after changing to double braces, the original error goes out but Index must be greater than or equal to 0 and less than the size of argument list is given. There are 21 in newData + extra id.toString(), should be exact 22...Swarth
Seems like a very good reason to abandon this approach altogether and to simply use a JSON encoder with some quickly knocked together anonymous objects. Considerably less bug prone.Rhoads
first time knowing that curly braces needs to be escaped in c# @formatted string.Xanthippe
F
8

You have 21 elements in newData but use 22 placeholders (numbered 0 to 21).

Also, you must escape literal '{' in your input data

Opening and closing braces are interpreted as starting and ending a format item. Consequently, you must use an escape sequence to display a literal opening brace or closing brace. Specify two opening braces ("{{") in the fixed text to display one opening brace ("{"), or two closing braces ("}}") to display one closing brace ("}"). Braces in a format item are interpreted sequentially in the order they are encountered. Interpreting nested braces is not supported.

http://msdn.microsoft.com/en-us/library/txafckwd.aspx

Feathered answered 29/1, 2013 at 0:21 Comment(1)
I missed id at the first time posting it, but in my code I do have it but still getting the error.Swarth
T
3

I've said as much in the comments, but I think it's worth an answer by now:

Don't use string.Format (in this case). It's slower, and less readable. Just use plain string concatenation with meaningful variable names if you need complex concatenations - these will be faster and more maintainable. Faster because for a fixed number of segments plain + is the fastest option due to compiler optimizations, and more maintainable because the reader can see the context within the string in which the variable is put.

As Hans Passant noted, it looks like you're making a javascript literal. If that's the case, consider a Json serializer like Json.NET instead:

JsonConvert.SerializeObject(new {
    cmd = "save magellan deal",
    data = new {
        id = 12345, AId = 1, CId = 2, CCId = 21,
        LA = "reidb", BA = "reidb", LSA = "reidb", BSA = "reidb",
        path = "aa", dscp = "Some description", SI = 11,
        CD = "2012-02-28", period = "2012-01-29",
        IsStatic = true, LSD = 1, LC = 1, RB = true,
    },
    Notes = "note note note",
    IsEE = true, RBy = 1, DPDD = "2011-12-03", LId = 45
})

While Json.NET does support DateTime serialization, there's not standardized format for dates in JS, so these are serialized as strings in an iso 8601 format. This might not be what you need, hence the date strings in this example - I'd try the iso format first, though, as that's the simplest solution.

Thinner answered 29/1, 2013 at 10:29 Comment(0)
K
2

In addition to escaping your curly braces also try changing your String[] definition to:

int id = 112;

String[] newData = {id.ToString(), "1", "2", "21", "reidb", "reidb", "reidb", "reidb", "aa", 
          "Some description", "11", "2012-02-28", "2012-01-29", "true", "1", "1", 
          "true", "note note note", "true", "1", "2011-12-03", "45"};

and change your String.Format to:

String cmd = String.Format(data,newData);
Kameko answered 29/1, 2013 at 0:49 Comment(1)
@Swarth - Or, as I was just typing, you only have two arguments to fill 22 places in the format string. And the literal curly braces need to be escaped as per Cédric Bignon.Rosellaroselle
U
1

What

String cmd = String.Format(data, id.toString(), newData);  

does is: trying to format the String data , using just 2 strings..not 22!!
Which ones?...1)id.ToString() and 2)newData.ToString()
Thats obviously wrong

How you can see that this is the problem...? Leave just {0} and {1} in data string and print it.It compiles ok and see what you get.
Of course you have to use {{ instead of { where you want a string literal

Fully working Solution:

int id = 112;

String[] newData = { id.ToString(),"1", "2", "21", "reidb", "reidb", "reidb", "reidb", "aa", 
                  "Some description", "11", "2012-02-28", "2012-01-29", "true", "1", "1", 
                  "true", "note note note", "true", "1", "2011-12-03", "45"};

String data = "{{ cmd: \"save magellan deal\", data: {{ id: {0} , AId: {1}, " +
                    "CId: {2}, CCId:{3}, LA: \"{4}\", BA: \"{5}\" , " +
                    "LSA: \"{6}\" , BSA: \"{7}\" , \"path: \"{8}\"," +
                    "dscp: \"{9}\", SI: \"{10}\", CD: \"{11}\", " +
                    "period: \"{12}\", IsStatic: {13}, LSD: {14}, LC: {15}, RB: {16},}} " +
                    "Notes: \"{17}\", IsEE: {18}, RBy: {19}, DPDD: \"{20}\", LId: {21} }} }}";


String cmd = String.Format(data, newData);
Utilitarian answered 29/1, 2013 at 1:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.