Using .ToString("E4") prints a number like 1.2345E+012.
How can I make it print one less number in the exponential part. In other words, print 1.2345E+12.
Thanks!
You can use a custom format string with the E indicator, which takes the minimum number of digits:
double value = 1234567890000;
Console.WriteLine(value.ToString("0.####E+0"));
// 1.2346E+12
You could always store '.ToString("E4")' in a string called "output". Then print "output" character by character until you read a "+" character in "output". Don't print the next character if it's a "0", keep checking for "0"s until you reach something that does not equal (!=) a "0" character and then print the last characters.
Try that code:
var number = 1234567890000;
var exponential = number.ToString("E4");
var splitted = exponential.Split('+');
var result = splitted.Length == 2 ? $"{splitted[0]}+{Convert.ToInt32(splitted[1])}" : exponential;
It takes the number, evaluates the exponential string and removes all leading zeros.
This is done by splitting at the + (if there is one, otherwise it's not neccessary and there won't be any leading zeros) and converting the string, of which the zero shall get removed, to a number. As numbers aren't stored with leading zeros, converting it back to a string removes the leading zeros.
If you want to prevent cases where E+0 is written at the end, check the converted string for 0 and if so use the first part of the splitted string without the last character.
Related
I'm writing some code to display a number for a report. The number can range from 1. something to thousands, so the amount of precision I need to display depends on the value.
I would like to be able to pass something in .ToString() which will give me at least 3 digits - a mixture of the integer part and the decimal part.
Ex:
1.2345 -> "1.23"
21.552 -> "21.5"
19232.12 -> "19232"
Using 000 as a format doesn't work, since it doesn't show any decimals, neither does 0.000 - which shows too many decimals when the whole part is larger than 10.
You could write an extension method for this:
public static string ToCustomString(this double d, int minDigits = 3)
{
// Get the number of digits of the integer part of the number.
int intDigits = (int)Math.Floor(Math.Log10(d) + 1);
// Calculate the decimal places to be used.
int decimalPlaces = Math.Max(0, minDigits - intDigits);
return d.ToString($"0.{new string('0', decimalPlaces)}");
}
Usage:
Console.WriteLine(1.2345.ToCustomString()); // 1.23
Console.WriteLine(21.552.ToCustomString()); // 21.6
Console.WriteLine(19232.12.ToCustomString()); // 19232
Console.WriteLine(1.2345.ToCustomString(minDigits:4)); // 1.235
Try it online.
I don't think this can be done with ToString() alone.
Instead, start by formatting the number with 2 trailing digits, then truncate as necessary:
static string FormatNumber3Digits(double n)
{
// format number with two trailing decimals
var numberString = n.ToString("0.00");
if(numberString.Length > 5)
// if resulting string is longer than 5 chars it means we have 3 or more digits occur before the decimal separator
numberString = numberString.Remove(numberString.Length - 3);
else if(numberString.Length == 5)
// if it's exactly 5 we just need to cut off the last digit to get NN.N
numberString = numberString.Remove(numberString.Length - 1);
return numberString;
}
Here's a regex, that will give you three digits of any number (if there's no decimal point, then all digits are matched):
#"^(?:\d\.\d{1,2}|\d{2}\.\d|[^.]+)"
Explanation:
^ match from start of string
either
\d\.\d{1,2} a digit followed by a dot followed by 1 or 2 digits
or
\d{2}\.\d 2 digits followed by a dot and 1 digit
or
[^.]+ any number of digits not up to a dot.
First divide your number and then call ToString() before the regex.
Simple way to implement this just write
ToString("f2") for two decimal number just change this fnumber to get your required number of decimal values with integer values also.
I'm trying to format a decimal with the following requirements:
Thousands are separated by spaces " "
Decimal point is delimited by a
comma "," (this is achieved by using the appropriate culture, in this
case Croatian)
There are two digits after the decimal point.
So far I got this:
String.Format(new CultureInfo("hr-HR"), "{0:# ##0.00}", input)
This works well if the number has 4 or more digits before the decimal point. For example the value 5500.5 gives me "5 500,50" and -5500.5 gives me "-5 500,50", which is what I want.
But if the number has fewer digits, I get a white space in front of the number. For example 500.5 gives me " 500,50" instead of "500,50". And with a negative number, the space is put between the minus sign and the digits: -500.5 gives me "- 500,50". So I can't simply trim the result. How can I achieve what I need?
You can use a custom NumberFormatInfo to format numbers.
var nfi = new NumberFormatInfo();
nfi.NumberGroupSeparator = " "; // set the group separator to a space
nfi.NumberDecimalSeparator = ","; // set decimal separator to comma
And then format the number using
number.ToString("N2", nfi); // numeric format with 2 decimal digits
This gives you
(5500.5).ToString("N2", nfi) // "5 500,50"
(-500.5).ToString("N2", nfi) // "-500,50"
(-5500.5).ToString("N2", nfi) // "-5 500,50"
The simplest approach may be to just check if input is over a 1000 / less than -1000 before formatting it this way.
if(input >= 1000 || input <= -1000){
// use String.Format(new CultureInfo("hr-HR"), "{0:# ##0.00}", input)
}else{
// just use input.ToString()?
}
There's probably a way to coerce string.format into doing what you want, but why overcomplicate the issue?
This is a very simple example:
class Program
{
static void Main(string[] args)
{
int val = 0;
Console.WriteLine(val.ToString()); // outputs: "0"
Console.WriteLine(val.ToString("#,#")); // outputs: "" <-- what if I want "0"!?!?
val = 1;
Console.WriteLine(val.ToString()); // outputs: "1"
Console.WriteLine(val.ToString("#,#")); // outputs: "1"
Console.Read();
}
}
There is a case where I have an int that contains a 0 value. I want this to appear as "0" but it's appearing as an empty string. Is it because 0 is the int's default value? Does the formatter assume that because it's default the output should be ""?
If you want 0, use #,0
# means optional
0 means mandatory
You can read more here: Custom Numeric Format Strings
The digit placeholder (#) is similar to the zero placeholder. It
defines the position of a digit within the resultant formatted string
and causes rounding after the decimal point. However, the digit
placeholder does not cause leading or trailing zeroes to be added to a
number where the original numeric value has no digit in the
appropriate position.
The digit placeholder has a side effect when converted a zero value to
a string. As the placeholder will not cause the creation of either
leading or trailing zeroes, when converting a zero value the resultant
string is empty.
C# Number to String Conversion
I want to get third and fourth letters from PlayerPrefs.GetString("String")
and Parse to int.
for example;
string playerLevelstr = PlayerPrefs.GetString("Player")[2] + PlayerPrefs.GetString("Player")[3];
//My Player string is "0012000000" but when I plus third and fourth letter, playerLevelstr should be "12" but it is "96".
int playerLevelint = int.Parse(playerLevelstr);
The indexer on a string returns a char.
If you use the + operator on chars together, it essentially does integer math on the two chars.
See this question for more information on that.
Though that means you should get 99 ('1' is 49, '2' is 50') not 96. But maybe that was a typo on one end or the other?
Regardless, you should either convert the chars to strings (.ToString() on them) or use the Substring function on the string instead. And don't forget your length/null checks!
This code PlayerPrefs.GetString("Player")[2] returns a char, which is being being converted to int (being the ASCII value of the character) when you add it to another char.
Do this instead:
string playerLevelstr = PlayerPrefs.GetString("Player").Substring(2,2);
I'm working with X12 EDI Files (Specifically 835s for those of you in Health Care), and I have a particular vendor who's using a non-HIPAA compliant version (3090, I think). The problem is that in a particular segment (PLB- again, for those who care) they're sending a code which is no longer supported by the HIPAA Standard. I need to locate the specific code, and update it with a corrected code.
I think a Regex would be best for this, but I'm still very new to Regex, and I'm not sure where to begin. My current methodology is to turn the file into an array of strings, find the array that starts with "PLB", break that into an array of strings, find the code, and change it. As you can guess, that's very verbose code for something which should be (I'd think) fairly simple.
Here's a sample of what I'm looking for:
~PLB|1902841224|20100228|49>KC15X078001104|.08~
And here's what I want to change it to:
~PLB|1902841224|20100228|CS>KC15X078001104|.08~
Any suggestions?
UPDATE: After review, I found I hadn't quite defined my question well enough. The record above is an example, but it is not necessarilly a specific formatting match- there are three things which could change between this record and some other (in another file) I'd have to fix. They are:
The Pipe (|) could potentially be any non-alpha numeric character. The file itself will define which character (normally a Pipe or Asterisk).
The > could also be any other non-alpha numeric character (most often : or >)
The set of numbers immediately following the PLB is an identifier, and could change in format and length. I've only ever seen numeric Ids there, but technically it could be alpha numeric, and it won't necessarilly be 10 characters.
My Plan is to use String.Format() with my Regex match string so that | and > can be replaced with the correct characters.
And for the record. Yes, I hate ANSI X12.
Assuming that the "offending" code is always 49, you can use the following:
resultString = Regex.Replace(subjectString, #"(?<=~PLB|\d{10}|\d{8}|)49(?=>\w+|)", "CS");
This looks for 49 if it's the first element after a | delimiter, preceded by a group of 8 digits, another |, a group of 10 digits, yet another |, and ~PLB. It also looks if it is followed by >, then any number of alphanumeric characters, and one more |.
With the new requirements (and the lucky coincidence that .NET is one of the few regex flavors that allow variable repetition inside lookbehind), you can change that to:
resultString = Regex.Replace(subjectString, #"(?<=~PLB\1\w+\1\d{8}(\W))49(?=\W\w+\1)", "CS");
Now any non-alphanumeric character is allowed as separator instead of | or > (but in the case of | it has to be always the same one), and the restrictions on the number of characters for the first field have been loosened.
Another, similar approach that works on any valid X12 file to replace a single data value with another on a matching segment:
public void ReplaceData(string filePath, string segmentName,
int elementPosition, int componentPosition,
string oldData, string newData)
{
string text = File.ReadAllText(filePath);
Match match = Regex.Match(text,
#"^ISA(?<e>.).{100}(?<c>.)(?<s>.)(\w+.*?\k<s>)*IEA\k<e>\d*\k<e>\d*\k<s>$");
if (!match.Success)
throw new InvalidOperationException("Not an X12 file");
char elementSeparator = match.Groups["e"].Value[0];
char componentSeparator = match.Groups["c"].Value[0];
char segmentTerminator = match.Groups["s"].Value[0];
var segments = text
.Split(segmentTerminator)
.Select(s => s.Split(elementSeparator)
.Select(e => e.Split(componentSeparator)).ToArray())
.ToArray();
foreach (var segment in segments.Where(s => s[0][0] == segmentName &&
s.Count() > elementPosition &&
s[elementPosition].Count() > componentPosition &&
s[elementPosition][componentPosition] == oldData))
{
segment[elementPosition][componentPosition] = newData;
}
File.WriteAllText(filePath,
string.Join(segmentTerminator.ToString(), segments
.Select(e => string.Join(elementSeparator.ToString(),
e.Select(c => string.Join(componentSeparator.ToString(), c))
.ToArray()))
.ToArray()));
}
The regular expression used validates a proper X12 interchange envelope and assures that all segments within the file contain at least a one character name element. It also parses out the element and component separators as well as the segment terminator.
Assuming that your code is always a two digit number that comes after a pipe character | and before the greater than sign > you can do it like this:
var result = Regex.Replace(yourString, #"(\|)(\d{2})(>)", #"$1CS$3");
You can break it down with regex yes.
If i understand your example correctly the 2 characters between the | and the > need to be letters and not digits.
~PLB\|\d{10}\|\d{8}\|(\d{2})>\w{14}\|\.\d{2}~
This pattern will match the old one and capture the characters between the | and the >. Which you can then use to modify (lookup in a db or something) and do a replace with the following pattern:
(?<=|)\d{2}(?=>)
This will look for the ~PLB|#|#| at the start and replace the 2 numbers before the > with CS.
Regex.Replace(testString, #"(?<=~PLB|[0-9]{10}|[0-9]{8})(\|)([0-9]{2})(>)", #"$1CS$3")
The X12 protocol standard allows the specification of element and component separators in the header, so anything that hard-codes the "|" and ">" characters could eventually break. Since the standard mandates that the characters used as separators (and segment terminators, e.g., "~") cannot appear within the data (there is no escape sequence to allow them to be embedded), parsing the syntax is very simple. Maybe you're already doing something similar to this, but for readability...
// The original segment string (without segment terminator):
string segment = "PLB|1902841224|20100228|49>KC15X078001104|.08";
// Parse the segment into elements, then the fourth element
// into components (bounds checking is omitted for brevity):
var elements = segment.Split('|');
var components = elements[3].Split('>');
// If the first component is the bad value, replace it with
// the correct value (again, not checking bounds):
if (components[0] == "49")
components[0] = "CS";
// Reassemble the segment by joining the components into
// the fourth element, then the elements back into the
// segment string:
elements[3] = string.Join(">", components);
segment = string.Join("|", elements);
Obviously more verbose than a single regular expression but parsing X12 files is as easy as splitting strings on a single character. Except for the fixed length header (which defines the delimiters), an entire transaction set can be parsed with Split:
// Starting with a string that contains the entire 835 transaction set:
var segments = transactionSet.Split('~');
var segmentElements = segments.Select(s => s.Split('|')).ToArray();
// segmentElements contains an array of element arrays,
// each composite element can be split further into components as shown earlier
What I found is working is the following:
parts = original.Split(record);
for(int i = parts.Length -1; i >= 0; i--)
{
string s = parts[i];
string nString =String.Empty;
if (s.StartsWith("PLB"))
{
string[] elems = s.Split(elem);
if (elems[3].Contains("49" + subelem.ToString()))
{
string regex = string.Format(#"(\{0})49({1})", elem, subelem);
nString = Regex.Replace(s, regex, #"$1CS$2");
}
I'm still having to split my original file into a set of strings and then evaluate each string, but the that seams to be working now.
If anyone knows how to get around that string.Split up at the top, I'd love to see a sample.