Do multiple leading '#' signs in format strings do anything? - c#

In some legacy .NET code I've come across a number of custom numeric format strings like this:
###,##0.00
What is the difference between this and:
#,#0.00
?
EDIT:
Here are some example inputs I've tried, all of which yield the same result for both masks: 1000000, 1000, 100, 10, 1.456, -30000, 0.002.
EDIT:
#Sahuagin suggested that these masks could be the same because of how the culture is set to group to three digits. However, even using this I can't demonstrate a difference:
var culture = new CultureInfo("en-US");
culture.NumberFormat.NumberGroupSizes = new[] { 1, 2, 3, 4 };
culture.NumberFormat.NumberGroupSizes.Dump();
1234567890.ToString("#,#0.00", culture).Dump(); // 1234,567,89,0.00
1234567890.ToString("###,#0.00", culture).Dump(); // 1234,567,89,0.00
More generally, I understand that # is an "optional" digit which won't create leading or trailing zeroes. However, it seems like just a single # before the decimal point is enough to get all leading digits. The MSDN docs seem to differentiate between # and ## but the explanation doesn't make much sense to me and I haven't found an example where it makes a difference.

# indicates a place where a digit will appear, if one exists in the number. Absent any such symbols, leading digits automatically appear (though you must have at least either one # or one 0, or no number will appear), but they are still useful as placeholders in some kinds of formats, for example a telephone number:
var value = 1234567890;
Console.WriteLine("{0:###-###-####}", value);
// outputs 123-456-7890
In your example of #,#0.00, I think that only manages to still format correctly (with groups of three) because , is a special grouping symbol, and the culture info is set to group digits in threes. Without that, you would get something like 123-45.67, if you used a - instead of a , for example.
Here is more specific information about , from MSDN:
The "," character serves as both a group separator and a number scaling specifier.
Group separator: If one or more commas are specified between two digit placeholders (0 or #) that format the integral digits of a number, a group separator character is inserted between each number group in the integral part of the output.
The NumberGroupSeparator and NumberGroupSizes properties of the current NumberFormatInfo object determine the character used as the number group separator and the size of each number group. For example, if the string "#,#" and the invariant culture are used to format the number 1000, the output is "1,000".
Number scaling specifier: If one or more commas are specified immediately to the left of the explicit or implicit decimal point, the number to be formatted is divided by 1000 for each comma. For example, if the string "0,," is used to format the number 100 million, the output is "100".
So in your first example of ###,##0.00, it could probably be reduced to #,0.00, if desired, although #,##0.00 is what I usually use since it is much more clear.

Related

Regex Pattern to Validate Text Input With Max Value and Max Decimal Place

I need to create a pattern for a "text" type input to only allow a number from 0 to a specific max value and at the same time and validate to a specific number of decimal places.
Quick example:
Max Value = 300.86
Max Decimal Places = 3
Valid inputs:
0
1
300
300.86
300.85
300.850
300.851
.2
0.3333
Invalid inputs:
-1
301
300.87
300.861
1,30.2
1,.0
,.1
Currently I only know how to validate number of decimal places using this pattern:
^[,0-9]*(.\d{1,{0}})?$
Note:
I can't use type=number because I can't use any pattern with that :(
please help
I think something like this, is what you're after:
^(300(?:\.(?:[0-7]\d{0,2}|8(?:[0-5]\d?|60?)?))?|[0-2]?\d{0,2}(?:\.\d{0,3})?)$
See it here at REGEX STORM.
(Had to tweak it there, to end in \r, because REGEX STORM wouldn't match $ with end of line even though multi-line was selected???)
Explanation
It has two parts. The latter [0-2]?\d{0,2}(?:\.\d{0,3})? test for numbers below 300. It optionally starts with 0, 1 or 2 ([0-2]?). Then any two digits can follow (\d{0,2}). Then, optionally, it's followed by a . which, if present, can be followed by up to three digits (decimals) ((?:\.\d{0,3})?).
The first part - 300(?:\.(?:[0-7]\d{0,2}|8(?:[0-5]\d?|60?)?))? - test for when the integer part is exactly 300. It may then optionally be followed by a decimal point, and one out of three cases:
[0-7]\d{0,2} a digit in the range 0 to 7, followed by up to two digits
8(?:[0-5]\d*|60*)? an 8 followed by a digit in the range 0 to 5, optionally followed by a digit (The [0-5]\d? alternation).
or the number 86 and an optionall 0 (the 60? alternation)
These parts are in a capturing group separated by an alternation - |. The whole expression must be at the start of the string (^) (or line with multi-line flag) and at the end of the same ($).
Edit
Done some tweaking 'cause some numbers wrongly failed.
Edit 2
Completely missed "the maximum number of decimals" part. Fixed. (Fooled by the "valid" example 0.3333)
I don't know anything about C# so I'll just have to assume that what I can do in Python, you can find some way to do in C#. I'll give you my suggestion in pseudocode (this is not meant to mirror Python).
maxValue = some number
nDecimals = some number
givenValue = text with some number to be tested
#split number on decimal; remove non-digit characters from each side
leftSideOfDecimal = Replace(pattern = '^(\d{1,3}(,\d{3})*)(\.\d*)$', replacement = '\1', givenValue)
leftSideOfDecimal = Replace(',', '', leftSideOfDecimal)
rightSideOfDecimal = Replace('^(\d{1,3}(,\d{3})*)(\.\d*)$', '\3', givenValue)
rightSideOfDecimal = Replace('\.','',rightSideOfDecimal)
leftSideOfDecimal = pass leftSideOfDecimal to function to change type from text to integer
if leftSideOfDecimal <= maxValue and numberOfCharacters(rightSideOfDecimal) == nDecimals:
do whatever you want
Alternatively, if you have a function by which you can split strings on a given character (like a decimal or comma), then you just split the input on the decimal, clean up the first side as in the code, and then proceed with the last three lines of the code above. That way would save you from having to use a mildly complicated regex.

Displaying a Integer with thousand seperator

i want to display a integer value with a thousand seperator. i found following ways:
int i = 0101010101;
Console.WriteLine(i.ToString("N0")); // 101.010.101
Console.WriteLine(i.ToString("#,#"));// 101.010.101
what's the difference / advantage of each?
There is at least one difference. If you test it with i = 0, then the "N0" format string outputs 0, and the "#,#" format string outputs nothing at all. As the documentation states:
Note that this specifier never displays a zero that is not a significant digit, even if zero is the only digit in the string. It will display zero only if it is a significant digit in the number that is being displayed.

Discount mask with regex

Is it possible to create a 'dynamic' discount mask that takes % or numbers as discount values? What is the simple way to do this?
the samples of valide input: -25% or 0.25 or -5$ not 0 and two digit after dot
Try
#"(\+|-)?(\d+(\.\d*)?|\.\d+)%?"
It will find:
123.23
12.4%
.34
.34%
45.
45.%
8
7%
34
34%
+2.55%
-1.75%
UPDATE
and with ...
#"(\+|-)?(\d+(,\d{3})*(?!\d)(\.\d*)?|\.\d+)%?"
... you can include thousands separators as well.
I must confess that my second regex expression looks like a cat had walked accross my keyboard. Here the explanation
(\+|-)? optionally ? a plus or a minus sign.
\d+(,\d{3})*(?!\d)(\.\d*)? one or more digits \d+ followed by any number of thousands separators plus three digits (,\d{3})*, not followed by any digit (?!\d) in order to disallow four digits in sequence, optionally followed by a decimal point and any number of digits (\.\d*)?.
|\.\d+ or alternatively a decimal point followed by at least one digit.
%? finally an optional percent sign.
If I understand your question right, you want something like this:
#"^[+-]?(?:\d*\.)?\d+[%$]?$"
That's partly based on your example of -5$. Usually, though, the $ would go in front, so you'd want something like:
#"^(?:\$(?!.*%))?[+-]?(?:\d*\.)?\d+%?$"
That would allow $-5.00, 10, or +20%, but block $5%.
Edit:
Running with Olivier's idea of allowing commas:
#"^(\$(?!.*%))?[+-]?(\d{1,3}((,\d{3})*|\d*))?(\.\d+)?\b%?$"
Expanded to make it easier to understand:
#"^ #Require matching from the beginning of the line
(\$(?!.*%))? #Optionally allow a $ here, but only if there's no % later on.
[+-]? #Optionally allow + or - at the beginning
(
\d{1,3} #Covers the first three numerals
((,\d{3})*|\d*) #Allow numbers in 1,234,567 format, or simply a long string of numerals with no commas
)? #Allow for a decimal with no leading digits
(\.\d+)? #Optionally allow a period, but only with numerals behind it
\b #Word break (a sneaky way to require at least one numeral before this position, thus preventing an empty string)
%? #Optionally allow %
$" #End of line

How do I format a number as a string, so that zero is replaced by the empty string

I need for this to work in a single format statement and to work for both ints and decimals:
For example:
int myInt=0;
decimal myDecimal=0.0m;
// ... Some other code
string formattedResult1=String.Format("{0}",myInt);
string formattedResult2=String.Format("{0}",myDecimal);
The expected results are:
"" (i.e., string.Empty) if the item to be formatted is zero
and a numeric value (e.g., "123.456" for the decimal version) if it isn't.
I need for this to occur exclusively as a result of the format specification in the format string.
This should do:
string formattedResult1 = string.Format("{0:0.######;-0.######;\"\"}", myInt);
The colon introduces a numeric format string. The numeric format string is divided into 3 parts with semicolons: part 1 is for positive numbers, part 2 for negative numbers, and part 3 for zeros. To define a blank string you need to delimit it with double quotes otherwise it doesn't like it.
See MSDN for the full syntax.
based from the accepted answer above i have done the same thing in microsoft "report builder"
this worked for me (shows 2 decimal places, blank for zero) :
,##0.00;-#,##0.00;""

Regular expression to detect whether input is a formatted number

Regular Expressions have always seemed like black magic to me and I have never been able to get my head around building them.
I am now in need of a Reg Exp (for validation putsposes) that checks that the user enters a number according to the following rules.
no alpha characters
can have decimal
can have commas for the thousands, but the commas must be correctly placed
Some examples of VALID values:
1.23
100
1,234
1234
1,234.56
0.56
1,234,567.89
INVALID values:
1.ab
1,2345.67
0,123.45
1.24,687
You can try the following expression
^([1-9]\d{0,2}(,\d{3})+|[1-9]\d*|0)(\.\d+)?$
Explanation:
The part before the point consists of
either 1-3 digits followed by (one or more) comma plus three digits
or just digits (at least one)
If then follows a dot also some digits must follow.
^(((([1-9][0-9]{0,2})(,[0-9]{3})*)|([0-9]+)))?(\.[0-9]+)?$
This works for all of your examples of valid data, and will also accept decimals that start with a decimal point. (I.e. .61, .07, etc.)
I noticed that all of your examples of valid decimals (1.23, 1,234.56, and 1,234,567.89) had exactly two digits after the decimal point. I'm not sure if this is coincidence, or if you actually require exactly two digits after the decimal point. (I.e. maybe you're working with money values.) The regular expression as I've written it works for any number of digits after the decimal point. (I.e. 1.2345 and 1,234.56789 would be considered valid.) If you need there to be exactly two digits after the decimal point, change the end of the regular expression from +)?$ to {2})?$.
try to use this regex
^(\d{1,3}[,](\d{3}[,])*\d{3}(\.\d{1,3})?|\d{1,3}(\.\d+)?)$
I know you asked for a regex but I think it's much saner to just call double.TryParse() and consider your input acceptable if that method returns true.
double dummy;
var isValid=double.TryParse(text, out dummy);
It won't match your testcases exactly; the major difference being that it is very lenient with commas (so it will accept two of your INVALID inputs).
I'm not sure why you care, but if you really do want comma strictness you could do a preprocessing step where you only check the validity of comma placement and then call double.TryParse() only if the string passes the comma placement test. (If you want to be truly careful, you'll have to honor the CultureInfo so you can know what character is used for separators, and how many digits there are between separators, in the environment your program finds itself in)
Either approach results in code that is more "obviously right" than a regex. For example, you won't have to live with the fear that your regex left out some important case, like scientific notation.

Categories