Easy way to check FormatString is valid? - c#

Is there an easy way to check if a format string is valid? For example the following is code that we use to test a number format string;
public static bool IsValidFormatStringNumber(string FormatString)
{
try
{
const decimal number = 0.056m;
var formattedNumber = number.ToString(FormatString);
return formattedNumber.Length > 0;
}
catch
{
return false;
}
}
We're trying to catch an exception or determine if the resulting string has no length. This test fails however as a format string of "hsibbur" (Any rubbish) results in a string of "hsaibbur", which has length.
We want to do the same test for Percent and Date format string.

If you just want to check for standard format strings, just check that your format strings are part of that list.
If you want to check for custom format strings (that are not "Other" or "Literal strings"), you can probably craft a regex to do it.
Other than that, since format strings can be arbitrary strings, I don't think validation even applies.

If FormatString is equal to formattedNumber, that could be another case for returning false.

Related

Input string was not in correct format error when parsing to int

I get error "Input string was not in correct format" when parsing to int.
But string is in correct format. I'm adding screenshot below.
The problem is that there must be some hidden characters in your a string variable (Carriage Return maybe?). Try int.Parse(a.Substring 0,4) as usually they are at the end of the string.
You could also clean the input where you are getting that value from.
I noticed you are doing multiple conversions. Are you sure it's a ("2016") that is causing the error?
if yes, then there must be hidden characters as other have suggested. The a.substring(0,4) would indeed remove any trailing characters. But if the first character is a hidden char, it would not.
string output = new string(input.Where(c => char.IsLetter(c) || char.IsDigit(c)).ToArray());
should clear out any possible hidden characters.
Maybe you can try something like this:
int x = Convert.ToInt32(a);
Furthermore you can try to use the .ToString() Methode of a to make it run more stable.
You can additionaly try to clear the string from all "non number" chars using Rexex:
/// <summary>
/// RegEx to extract all non numeric values.
/// </summary>
private static readonly Regex rxNonDigits = new Regex(#"[^\d.,-]+");
Use it as follows to clear:
String a2 = rxNonDigits.Replace(a, "");
I think you are using REST API with JSON or passing whole string in query string i.e JSON formatted string, then you should use
a = new JavaScriptSerializer().Deserialize(a, null).ToString();
x = int.Parse(a);

Contains doen't check in the date range

I have a date range come like this,
string ActualReleaseDates ="7/8/2016, 7/9/2016, 7/11/2016,7/3/2016,7/10/2016,7/17/2016,7/24/2016,7/31/2016";
string NewsReleasedDate ="07/11/2016";
I want to check NewsReleaseDate is inside the ActualReleaseDates
But in the following code it return as a false.
if (ActualReleaseDates.Split(',').Contains(NewsReleasedDate.TrimStart(new Char[] { '0' })))
{
//some code here
}
The immediate problem is that after splitting your ActualReleaseDates string, there isn't an entry of "7/11/2016"... instead, there's an entry of " 7/11/2016"... note the space.
But more fundamentally, just trimming the start of NewsReleasedDate won't help if the value is something like "07/08/2016"... what you should be doing is handling these values as dates, rather than as strings:
Split ActualReleaseDates by comma, then parse each value (after trimming whitespace) in an appropriate format (which I suspect is M/d/yyyy) so that you get a List<DateTime>.
Parse NewsReleasedDate in the appropriate format, which I suspect is MM/dd/yyyy, so you get a DateTime.
See whether the parsed value from the second step occurs in the list from the first step.
(I'd personally recommend using Noda Time and parsing to LocalDate values, but I'm biased...)
Fundamentally, you're trying to see whether one date occurs in a list of dates... so make sure you get your data into its most appropriate representation as early as possible. Ideally, avoid using strings for this at all... we don't know where your data has come from, but if it started off in another representation and was converted into text, see if you can avoid that conversion.
The white space problem. You can use trim() and ' 7/11/2016' will be '7/11/2016'
var ActualReleaseDates = "7/8/2016, 7/9/2016, 7/11/2016,7/3/2016,7/10/2016,7/17/2016,7/24/2016,7/31/2016";
var NewsReleasedDate = "07/11/2016";
var splitActualReleaseDates = ActualReleaseDates.Split(',').Select(x => x.Trim());
if (splitActualReleaseDates.Contains(NewsReleasedDate.TrimStart(new Char[] { '0' })))
{
}
You can use linq to convert your strings into DateTime objects and compare them instead of strings
string ActualReleaseDates ="7/8/2016,7/9/2016,7/11/2016,7/3/2016,7/10/2016,7/17/2016,7/24/2016,7/31/2016";
string NewsReleasedDate ="07/11/2016";
var releaseDates = ActualReleaseDates.Split(',').Select(x => DateTime.Parse(x));
var newsReleased = DateTime.Parse(NewsReleaseDate);
if (releaseDates.Contains(newsReleased))
{
//some code here
}
please note that DateTime is parsed respectively to the current Culture. You can use DateTime.ParseExact if you want to specify exact date format.
You can Prase to DateTime before doing the query like this:
(I think this is the most accurate and guaranteed way to compare dates)
Func<string, DateTime> stringToDate = s => DateTime.ParseExact(s.Trim(), "M/d/yyyy",
CultureInfo.InvariantCulture);
DateTime newReleaseDateTime = stringToDate(NewsReleasedDate);
bool result = ActualReleaseDates.Split(',').Select(x => stringToDate(x))
.Contains(newReleaseDateTime);
It returns false because of the date 07/11/2016 stored in NewsReleasedDate is stored as string with a '0' at the begining. And in the ActualReleaseDates string you have white spaces between the ',' and numbers.
Try to rewrite theese strings like this :
ActualReleaseDates ="7/8/2016,7/9/2016,7/11/2016,7/3/2016,7/10/2016,7/17/2016,7/24/2016,7/31/2016"; // white spaces removed.
and the variable like this :
NewsReleasedDate ="7/11/2016"; // 0 removed
This is my code example :
string ActualReleaseDates = "7/8/2016,7/9/2016,7/11/2016,7/3/2016,7/10/2016,7/17/2016,7/24/2016,7/31/2016";
string NewsReleasedDate = "7/11/2016";
string[] dates = ActualReleaseDates.Split(',');
Console.WriteLine(dates.Contains(NewsReleasedDate));
This is not the best way to compare dates, you can use Date class which is usefull to do this kind of comparations.

formatting decimals using string format

public static string PadZero(this double number, int decimalPlaces)
{
var requiredFormat = "0." + "".PadRight(decimalPlaces, '0');
var something = $"{number:requiredFormat}";
return number.IsNotZero() ? something: string.Empty;
}
This is a helper function to pad zeros to a double number, user can pass the number of zeros that is required to be padded through decimalPlaces.
Above function fails my unit tests, output received is {requiredFormat} in all test cases.
I have just replaced: var something = $"{number:0.00}"; with a generic variable requiredFormat that can handle any number of zero padding.
There are two problems with your example. The first is that the value of something is not going to produce a string that can be used to format a number. The second is that you are not using something to perform a number format by using string.format.
So first off, the statement:
var something = $"{number:requiredFormat}";
is not going to give you the result that you want, which would be a string that looks something like:
{0:0.0000}
Try changing the code to read:
var something = $"{{0:{requiredFormat}}}";
If you do Console.WriteLine(something) after that statement executes you can inspect the value of something to make sure it is what you are looking for.
After that, change this line:
return number.IsNotZero() ? something: string.Empty;
to read:
return number.IsNotZero() ? string.Format(something, number) : string.Empty;
Even with Interpolated Strings, you have to build the variable format and apply it in two separate steps.
Hope that helps.

Formatting String With LEading Zero's

I am trying to convert an object (coming from a SQL server), into a integer so I can format the number to have the correct amount of zero's in front of it.
For example:
If I were to have 25.6, I would need it to be 0025.6.
Now I have looked online on how to do this, but the methods that I have seen people post are not working for me. I am not entirely sure why. I am trying to format GlobalVariables.grossweightafter. I read the value GlobalVariables.grossweight from the SQL server, but then when I TryParse it, it loses its value. The code I have is below:
while (TransferRecord.Read())
{
//Pulling data from the SQL server. getting data for every line of code as specified.
GlobalVariables.baledate = TransferRecord["keyprinter_datetime"];
GlobalVariables.baleline = TransferRecord["pulp_line_id"];
GlobalVariables.baleid = TransferRecord["bale_id"];
GlobalVariables.grossweight = TransferRecord["bale_gross_weight"];
GlobalVariables.grossweightflag = TransferRecord["gross_value_flag"];
GlobalVariables.baleairdrypercent = TransferRecord["bale_airdry_pct"];
GlobalVariables.airdryflag = TransferRecord["airdry_value_flag"];
//Converting the date, and the baleid to fit in the string.
DateTime.TryParse(GlobalVariables.baledate.ToString(), out GlobalVariables.baledateafter);
int.TryParse(GlobalVariables.baleid.ToString(), out GlobalVariables.baleidafter);
int.TryParse(GlobalVariables.grossweight.ToString(), out GlobalVariables.grossweightafter);
GlobalVariables.grossweightafter.ToString("0000.0");
//Calling the WriteData method.
WriteData();
}
So I was wondering if anyone can catch what I am doing wrong, or they can help me out on the correct way to go about this.
What #Hans Passant was saying is that you need to assign the value returned from .ToString. That line should be:
GlobalVariables.grossweightafter = GlobalVariables.grossweightafter.ToString("0000.0");
The last lines should be
if(int.TryParse(GlobalVariables.grossweight.ToString(), out GlobalVariables.grossweightafter))
{
string grossWeightAfter = GlobalVariables.grossweightafter.ToString("0000.0");
//you need to save the string returned from the ToString-method somewhere or it will be lost.
///Alternatively, if GlobalVariables can contain strings aswell:
GlobalVariables.grossweightafter = GlobalVariables.grossweightafter.ToString("0000.0");
}
else
{
//React on value not being an int
}
Maybe you should try to use double.TryParse() method instead of int.TryParse(), because int does not have fractional part?
Also, you need to store ToString() result to a string variable. Your code should be like this:
GlobalVariables.grossweightafterstring = GlobalVariables.grossweightafter.ToString("0000.0");

Formatting string dates with String.Format()

Just curious...
So I get that if I convert the string version of the date to a DateTime object and pass it into the String.Format() method, then I"ll get the desired results.
String.Format("The date is {0:MMMM dd, yyyy}", DateTime.Parse("05-22-2012"));
"The date is May 22, 2012"
But why doesn't this work?
String.Format("The date is {0:MMMM dd, yyyy}", "05-22-2012")
"The date is 05-22-2012"
Sorry if this is a stupid question, but I'm just trying to understand how this works.
Thanks
The other answers here hit on salient points, but let's put them all together an examine how String.Format works.
It has five overloads, but we're going to talk only about the one that they all redirect to (this is not the actual code, if you want to see it with Reflector or ILSpy, you will find it in StringBuilder.AppendFormat). This is simplified for easy understanding.
public static string Format(IFormatProvider provider, string format, params object[] args)
{
StringBuilder sb = new StringBuilder();
// Break up the format string into an array of tokens
Token[] tokens = ParseFormatString(format);
foreach (Token token in tokens)
{
switch (token.TokenType)
{
// A Text token is just some text to output directly
case TokenType.Text:
sb.Append(token.Text);
break;
// An Index token represents something like {0} or {2:format}
// token.Index is the argument index
// token.FormatText is the format string inside ('' in the first example, 'format' in the second example)
case TokenType.Index:
{
object arg = args[token.Index];
IFormattable formattable = arg as IFormattable;
if (formattable != null && token.FormatText.Length > 0)
{
// If the argument is IFormattable we pass it the format string specified with the index
sb.Append(formattable.ToString(token.FormatText, provider));
}
else
{
// Otherwise we just use Object.ToString
sb.Append(arg.ToString());
}
}
break;
}
}
return sb.ToString();
}
In your question you ask why the format string doesn't get applied when you pass "05-22-2012". As Guffa said, that is not a DateTime object, it is a String object.
As GSerjo said, a String is not IFormattable. Strings are not formattable because formatting is the process of converting something into a String. A string is already a string!
So you can see that when the Format method gets to indexer, arg will not be IFormattable and it will simply call ToString. Calling ToString on a string simply returns itself, it's already a string.
In summary, if your format string contains an index with an inner-format string (e.g. {0:format}), that inner-format string will only be applied if the associated argument is IFormattable and it knows what to do with the format string you give it.
A custom datetime format only works on a DateTime value. If you are using a string instead, the format will be ignored because there is only one way to output a string.
Because "05-22-2012" is not IFormattable, DateTime.Parse("05-22-2012") it's DateTime
please look here for more examples
String Format for DateTime
Custom Date and Time Format Strings

Categories

Resources