Parsefloat with dot seperator - javascript

I have different numbers from 100.000 to 3.000.000 saved as a String. I Want to convert them into a number in exact the same format with the parsefloat function and sum them after it. With numbers under 1 million and only one dot it will working, with a number over one million it deletes the last numbers after the dot. for example when the productionItem.calculationResult.stromKwh = 1.358.149 the result it 1.358.
result is 1358.149 parseFloat(String(productionItem.calculationResult.stromKwh).replace('.','').replace(',','.'));
result is 1.358
parseFloat(String(productionItem.calculationResult.stromKwh).replace(',','.'));

First of all you need to understand that different locales use different number formatting characters. In english locales, decimals are separated using a dot (3.14159265) and thousands are separated using commas (1,000,000 is a million).
In german locales, these are reversed. Your numbers are formatted according to german locale rules.
Programming languages almost always use english locale conventions but without thousands separators. The dot is interpreted as the decimal point. parsefloat() parses numbers as JavaScript would do it, using the dot as the decimals separator.
Sadly, JavaScript has locale-specific number formatting (toLocaleString()) but no corresponding parsing functions. There are libraries which provide these, have a look at How do I convert String to Number according to locale (opposite of .toLocaleString)? for a discussion.

Related

Keep trailing or leading zeroes on number

Is it possible to keep trailing or leading zeroes on a number in javascript, without using e.g. a string instead?
const leading = 003; // literal, leading
const trailing = 0.10; // literal, trailing
const parsed = parseFloat('0.100'); // parsed or somehow converted
console.log(leading, trailing, parsed); // desired: 003 0.10 0.100
This question has been regularly asked (and still is), yet I don't have a place I'd feel comfortable linking to (did i miss it?).
Fully analogously would be keeping any other aspect of the representation a number literal was entered as, although asked nowhere near as often:
console.log(0x10); // 16 instead of potentially desired 0x10
console.log(1e1); // 10 instead of potentially desired 1e1
For disambiguation, this is not about the following topics, for some of which I'll add links, as they might be of interest as well:
Padding to a set amount of digits, formatting to some specific string representation, e.g. How can i pad a value with leading zeroes?, How to output numbers with leading zeros in JavaScript?, How to add a trailing zero to a price
Why a certain string representation will be produced for some number by default, e.g. How does JavaScript determine the number of digits to produce when formatting floating-point values?
Floating point precision/accuracy problems, e.g. console.log(0.1 + 0.2) producing 0.30000000000000004, see Is floating point math broken?, and How to deal with floating point number precision in JavaScript?
No. A number stores no information about the representation it was entered as, or parsed from. It only relates to its mathematical value. Perhaps reconsider using a string after all.
If i had to guess, it would be that much of the confusion comes from the thought, that numbers, and their textual representations would either be the same thing, or at least tightly coupled, with some kind of bidirectional binding between them. This is not the case.
The representations like 0.1 and 0.10, which you enter in code, are only used to generate a number. They are convenient names, for what you intend to produce, not the resulting value. In this case, they are names for the same number. It has a lot of other aliases, like 0.100, 1e-1, or 10e-2. In the actual value, there is no contained information, about what or where it came from. The conversion is a one-way street.
When displaying a number as text, by default (Number.prototype.toString), javascript uses an algorithm to construct one of the possible representations from a number. This can only use what's available, the number value, also meaning it will produce the same results for two same numbers. This implies, that 0.1 and 0.10 will produce the same result.
Concerning the number1 value, javascript uses IEEE754-2019 float642. When source code is being evaluated3, and a number literal is encountered, the engine will convert the mathematical value the literal represents to a 64bit value, according to IEEE754-2019. This means any information about the original representation in code is lost4.
There is another problem, which is somewhat unrelated to the main topic. Javascript used to have an octal notation, with a prefix of "0". This means, that 003 is being parsed as an octal, and would throw in strict-mode. Similarly, 010 === 8 (or an error in strict-mode), see Why JavaScript treats a number as octal if it has a leading zero
In conclusion, when trying to keep information about some representation for a number (including leading or trailing zeroes, whether it was written as decimal, hexadecimal, and so on), a number is not a good choice. For how to achieve some specific representation other than the default, which doesn't need access to the originally entered text (e.g. pad to some amount of digits), there are many other questions/articles, some of which were already linked.
[1]: Javascript also has BigInt, but while it uses a different format, the reasoning is completely analogous.
[2]: This is a simplification. Engines are allowed to use other formats internally (and do, e.g. to save space/time), as long as they are guaranteed to behave like an IEEE754-2019 float64 in any regard, when observed from javascript.
[3]: E.g. V8 would convert to bytecode earlier than evaluation, already exchanging the literal. The only relevant thing is, that the information is lost, before we could do anything with it.
[4]: Javascript gives the ability to operate on code itself (e.g. Function.prototype.toString), which i will not discuss here much. Parsing the code yourself, and storing the representation, is an option, but has nothing to do with how number works (you would be operating on code, a string). Also, i don't immediately see any sane reason to do so, over alternatives.

JavaScript function parseFloat() fails for negative values in certain locales

While working with locale translation and parsing decimal numbers from text to numerical values in Angular 10, I came across the following problem:
Consider the string value value = "-35.17 %". I want to convert this a numerical value using parseFloat(value). This works fine for application locale en-US.
However, if the user changes application locale to nb-NO (Norwegian), the parsing fails, resulting in a NaN.
The reason for this is that the Norwegian locale uses a different character for the negative prefix (− instead of -).
The workaround for this particular issue is simple, by performing a .replace("−", "-") on the string before parsing, but shouldn't JavaScript be able to handle parsing of both these characters? Is it only safe to perform parsing on locale en-US?
The JavaScript function parseFloat() needs an input string that meets certain requirements, including (but not limited to) the following:
If parseFloat encounters a character other than a plus sign (+), minus sign (- U+002D HYPHEN-MINUS), numeral (0–9), decimal point (.), or exponent (e or E), it returns the value up to that character, ignoring the invalid character and characters following it.
Localized strings may contain characters that does not meet those requirements.

Add trailing zeros to an integer without converting to string in JS?

I'm looking to add decimals to the end of my integer. As an example:
15 => 15.00
The problem with methods like toFixed is that it will convert it into a string. I've tried to use parseFloat() and Number() on the string, but it'll convert it back to an integer with no decimals.
Is this possible? If not, can someone explain to me the logic behind why this isn't possible?
EDIT: Welp the intent was to display the number as a number, but from the going consensus, it looks like the way the only way to go about it is to use a string. Found an answer on the why: https://stackoverflow.com/a/17811916/8869701
The problem you are finding is that all numbers in javascript are floats.
a = 0.1
typeof a # "number"
b = 1
typeof b # number
They are the same.
So there is no real way to convert to from an integer to a float.
This is the reason that all of the parseFloat etc are string methods for reading and writing numbers from strings. Even if you did have floats and integers, specifying the precision of a number only really makes sense when you are displaying it to a user, and for this purpose it will be converted to a string anyway.
Depending on your exact use case you will need to use strings if you want to display with a defined precision.
When working with numbers 15 and 15.00 are equal. It wouldn't make any sense to use memory to store those trailing or leading zeros.
If that information is needed it is usually for displaying purposes. In that case a string is the right choice.
In case you need that value again you can parse the string as a number.

Extracting integer from strings representing currency values

I have a stream of strings representing currency values from where I need to extract integers.
These strings may or may not have characters such as "$", "€", "-", space "." and "," that can alternate to separate decimals and digit groups.
These are the examples of strings and the value that I need to extract from them example:
"1,423,433.00" = 1423433
"1.355,22€" = 1355
" CAD$764.35" = 764
"$734242" = 734242
"$ 234.234,55" = 234234
"545,767$" = 545767
"765 778 00" = 765778
"765.823,888" = 765.823
I tried to use
.replace(/[^\d]/g, '');
but "$ 234.234,55" results is 23423455 and I need 234234 without the decimals. I guess I need to treat the decimals first.
And I also have cases where decimals are separated by "," or "." and can have 3 digits, ex: "1.365.823,803" or "12244.222".
In cases where I have "123.444" what leads me to know that the "." is not for decimals is that the number is never inferior to 10000.
How can I implement a function to extract these numbers?
EDIT:
I think the first step would be to remove all characters except "," or ".".
Than, we can find the decimal symbol, looking for the first symbol from the left.
If it comes after 2 digits, than we know its a decimal symbol.
If it comes after 3 digits, we look for the next symbol to see if it is different.
If it is the same than the first one is not a decimal symbol.
If it is different, than the first one is decimal.
If there's no other symbol, we know the first one is decimal because all numbers are superior to 1000, so if we have 1233.444 we know the "." is the decimals symbol.
If you want to get rid of the decimal part of the number and you a sure always is gonna come after a dot symbol you can use the next set of steps to remove the decimal part and get only the value.
' CAD$764.35'.split('.')[0].replace(/[^\d]/g, ''); // 764
In my opinion a better approach would be to remove all non number/dot characters from the string using replace and a regex, parse the string to a number.
To support all the cases you have, first you must analyze the string and verify which separation symbol is using and adjust the regular expression accordingly. When you use parseInt to coarse the string to a number you don't have to care if the decimal separation symbol is , or ..
parseInt('3452,90') // 3452
parseInt('3452.90') // 3452
But you must remove the other separation symbols from the string or this will cause a bug when you try to parse them.
parseInt('3,452.90') // 3
If I were you, I'd not try to reinvent the wheel. I suggest you a js library called numeral js which can handle the problems with the different currency and decimal formats.
For instance:
numeral("$ 234.234,55")
would output:
234.23455
Check it out for more examples.
You can simply use this
$(document).ready(function(){
myString = "CAD$764.35";
myString = myString.replace ( /[^\d.]/g, '' );
alert(myString);
});
DEMO

JSON.parse parses / converts big numbers incorrectly

My problem is really simple but I'm not sure if there's a "native" solution using JSON.parse.
I receive this string from an API :
{ "key" : -922271061845347495 }
When I'm using JSON.parse on this string, it turns into this object:
{ "key" : -922271061845347500 }
As you can see, the parsing stops when the number is too long (you can check this behavior here). It has only 15 exact digits, the last one is rounded and those after are set to 0. Is there a "native" solution to keep the exact value ? (it's an ID so I can't round it)
I know I can use regex to solve this problem but I'd prefer to use a "native" method if it exists.
Your assumption that the parsing stops after certain digits is incorrect.
It says here:
In JavaScript all numbers are floating-point numbers. JavaScript uses
the standard 8 byte IEEE floating-point numeric format, which means
the range is from:
±1.7976931348623157 x 10308 - very large, and ±5 x 10-324 - very small.
As JavaScript uses floating-point numbers the accuracy is only assured
for integers between: -9007199254740992 (-253) and 9007199254740992
(253)
You number lies outside the "accurate" range hence it is converted to the nearest representation of the JavaScript number. Any attempt to evaluate this number (using JSON.parse, eval, parseInt) will cause data loss. I therefore recommend that you pass the key as a string. If you do not control the API, file a feature request.
The number is too big to be parsed correctly.
One solution is:
Preprocessing your string from API to convert it into string before parsing.
Preform normal parsing
Optionally, you could convert it back into number for your own purpose.
Here is the RegExp to convert all numbers in your string (proceeded with :) into strings:
// convert all number fields into strings to maintain precision
// : 922271061845347495, => : "922271061845347495",
stringFromApi = stringFromApi.replace(/:\s*(-?\d+),/g, ': "$1",');
Regex explanation:
\s* any number of spaces
-? one or zero '-' symbols (negative number support)
\d+ one or more digits
(...) will be put in the $1 variable

Categories