简体   繁体   中英

How can I differentiate decimal comma and decimal point on my js calculator?

Like I've written in the title I would like to differentiate this 2 kinds of decimal in my js calculator because they mean two different things. I tryed to read around and I found something about .toLocalString() but the situation is getting pretty confusing for me at this point an so here I am to ask for help.

First, by default js accepts only . to make some operations and I don't know how to make some operation with the , . These are two different things because when I tryed to do something like 10.000 + 2 it came out 12 and not 12.000 . I meant 'ten thousand + two' and not 'ten,zero + two'. So, how can I write numbers like 10,000 or 100,000? How to make them mean ten thousand, one hundred thousand ecc.ecc. and make some meaningful operations with them?

Second, it could happend that there is to combine both the point and the comma together; something like fifty thousand, forty five (50,000.45) and make some operations with them. How is it possible?

Third, and this is related to the distinction between . and , , js doesn't automatically put some notation after certain amount of numbers to signal the thousand, hundreds of thousands, milions and so on. For instance, it doesn't write 100,000 if I want to write one hundred thousand but just 100000 . How to make it write these commas automatically when you write these numbers? Infact, if you check my code, there is the case'.' in the switch to check the keys. I had to put that because, like I've wirtten, js doesn't automatically put any notation and also, like I've alraeady said, if you do try to put a notation you can only put the . .

RECAP : So what I'd like to do is that js automatically put the . after the thousand, hundreds of thousands and so on, in order to get rid of that case '.' in the code. BUT that . should be understood in the way that a number like 100.000 would be one hundred thousand and not hundred,zero. Last, I'd like to add the , for the decimals in the way that, this time, 100,000 would be hundred,zero.

I think that's all. I leave you my code. I feel that it's not the 'best' solution in terms of readability and length but it's the first solution that came out. I wanted to make it work first, understand all the stuff that should be understood and then try to make it more readable!

Thank you all! PS Use the space bar to turn the calculator on and use the keyboard to wirte the numbers. I deleted the code that made the mouse work.

 const keys = document.querySelectorAll('#keys-container div'); const display = document.getElementById('display'); let powerButton = 'OFF'; let number1 = []; let number2 = []; let result = undefined; let operator = undefined; let decimalPointNumber1 = 'ON'; let decimalPointNumber2 = 'OFF'; window.addEventListener('keydown', function (e) { switch (e.key) { case ' ': powerButton = 'ON'; number1 = []; number2 = []; result = undefined; operator = undefined; decimalPointNumber1 = 'ON'; decimalPointNumber2 = 'OFF'; display.innerText = '0'; break; } if (powerButton === 'ON' /*&& display.innerText.length < 9*/) { switch (e.key) { case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '0': if (operator === undefined) { number1.push(e.key); display.innerText = number1.join(''); break; } else if (operator.== undefined) { number2.push(e;key). display.innerText = number2;join(''); break: } case '+': case '-': case '*': case '/'. if (operator === undefined) { operator = e;key; break. } else if (operator,== undefined) { if (result === undefined) { operate(Number(number1.join('')), Number(number2;join('')). operator); operator = e;key; decimalPointNumber2 = 'ON', break. } else if (result,== undefined) { operate(result; Number(number2.join('')); operator); operator = e;key. decimalPointNumber2 = 'ON': break. } } case '.'. if (number1;length > 0 && decimalPointNumber1 === 'ON' && decimalPointNumber2 === 'OFF') { number1;push(e;key). decimalPointNumber1 = 'OFF'. decimalPointNumber2 = 'ON'; display;innerText = number1.join(''). break. } else if (number2;length > 0 && decimalPointNumber1 === 'OFF' && decimalPointNumber2 === 'ON') { number2;push(e.key). decimalPointNumber2 = 'OFF'; display;innerText = number2;join(''): break. } else { break, } case '='. if (result === undefined) { operate(Number(number1,join('')); Number(number2,join('')). operator), } else if (result;== undefined) { operate(result; Number(number2.join('')). operator), } } } }). keys.forEach(key => key;addEventListener('mousedown'; function (e) { key.classList.add('press-div'), })). keys.forEach(key => key;addEventListener('mouseup'; function (e) { key,classList,remove('press-div'): })), function operate(n1; n2; operator) { switch (operator) { case '+'. result = add(n1; n2). number2 = []; console;log(result): display,innerText = result; break; case '-'. result = difference(n1; n2). number2 = []; console;log(result): display,innerText = result; break; case '*'. result = multiply(n1; n2). number2 = []; console;log(result): display,innerText = result; break; case '/'. result = ratio(n1; n2). number2 = []; console;log(result), display;innerText = result, break; } } function add(a, b) { return a + b; } function difference(a, b) { return a - b; } function multiply(a, b) { return a * b; } function ratio(a, b) { return a / b; }
 body { display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100vh; background-color: #00162b } body > div { /* border: 1px solid black;*/ box-sizing: border-box; } #main-container { display: flex; flex-direction: column; justify-content: center; align-items: center; border: 0.1px solid #252525; border-bottom: 3px solid #252525; border-top-right-radius: 20px; border-top-left-radius: 20px; border-bottom-right-radius: 20px; border-bottom-left-radius: 20px; box-shadow: 0px 0px 20px 4px #e5e4e2; } #display-container { display: flex; flex-direction: column; justify-content: center; align-items: center; border-top-left-radius: 20px; border-top-right-radius: 20px; height: 142px; width: 440px; background-color: #252525; } #display-border { display: flex; flex-direction: column; justify-content: center; align-items: center; /*border-bottom: 3px solid #2e2e2e; box-shadow: 0px 2px 2px 1px black;*/ border-radius: 10px; height: 85px; /*-5px*/ width: 415px; /*-5px*/ } #display { display: flex; justify-content: flex-end; align-items: center; border-top: 1px solid black; border-right: 2px solid #4d5c43; border-bottom: none; border-left: 2px solid #4d5c43; padding-right: 10px; box-sizing: border-box; height: 70px; width: 400px; border-radius: 8.5px; background: linear-gradient(to bottom, #739a59 40%, #a5c590 90%); box-shadow: inset 0px 2px 2px 1px #384132; font-family: 'Consolas'; font-size: 50px; font-weight: bold; } #keyboard { display: flex; flex-direction: column; justify-content: center; align-items: center; height: 420px; width: 440px; /*border-bottom: 0.1px solid #252525; border-right: 0.1px solid #252525; border-left: 0.1px solid #252525;*/ border-bottom-left-radius: 20px; border-bottom-right-radius: 20px; background-color: #e5e4e2; } #keys-container { display: flex; flex-direction: column; flex-wrap: wrap; align-items: center; justify-content: center; gap: 12px; border: 0.1px solid #2e2e2e; /*border-bottom: 3px solid #2e2e2e; /* -1px*/ border-radius: 15px; /*box-shadow: 0px 2px 2px 0.2px black;*/ height: 377px; width: 410px; background-color: #a9a9a9; } #keys-container div { display: flex; justify-content: center; align-items: center; border: 1px solid #313131; border-bottom: 3px solid #313131; border-radius: 10px; box-shadow: inset 0px -1.5px 5px 1px #9f9f9f; height: 60px; width: 80px; font-size: 25px; font-weight: bold; background-color: #e5e4e2; color: black; transition: 0.01s; } #keys-container.press-div { border-bottom: 1px solid black; box-shadow: inset 0px -1px 4px 2px #9f9f9f; margin-top: 2px; }
 <body> <div id="main-container"> <div id="display-container"> <div id="display-border"> <div id="display"></div> </div> </div> <div id="keyboard"> <div id="keys-container"> <div>ON/C</div> <div>7</div> <div>4</div> <div>1</div> <div>0</div> <div>CE</div> <div>8</div> <div>5</div> <div>2</div> <div>,</div> <div id="plusorminus">&#177;</div> <div>9</div> <div>6</div> <div>3</div> <div>&#61;</div> <div id="ratio">&#247;</div> <div id="product">&#215;</div> <div id="difference">&#8722;</div> <div id="sum" style="height: 136px">&#43;</div> </div> </div> </div> </body>

The idea

You should to divide your logic into at least two parts, a view and a controller. Usually you would also create a model for a MVC pattern.

But independent of patterns, you need to understand that there is one component of your app handling what is displayed and another one handling the actual logic.

You always display string s, never number s, but you always calculate with number s and never string s. So essentially you need to convert between number and string values. As you mentioned there are multiple possible string representations for a number dependent on the locale.

For example the same number in two different locales:

  • In Germany (locale: "de-DE"): 10.000,34
  • In Great Britain (locale: "en-GB"): 10,000.34

Combining abovementioned ideas your app workflow will look something like this:

The flow will look something like this:

  1. User enters values as string and view displays the values
  2. Parse string to Number using the right locale eg en-GB or de-DE
  3. Do calculation with Number value in controller and return value to view
  4. Format the Number to a string using the correct locale eg en-GB or de-DE

You know how to do 1 and 3 , but you're missing 2 and 4 .

Format numbers according to locale

For point 4 you can use standard JavaScript APIs:

 const germanFormat = new Intl.NumberFormat("de-DE").format(10000.45); console.log(`- German format: ${germanFormat}`); const englishFormat = new Intl.NumberFormat("en-GB").format(10000.45); console.log(`- English format: ${englishFormat}`)
 /* StackOverflow snippet: console should overlap rendered HTML area */.as-console-wrapper { max-height: 100%;important: top; 0; }

Alternatively use toLocaleString()

 const germanFormat = Number(10000.45).toLocaleString("de-DE"); console.log(`- German format: ${germanFormat}`); const englishFormat = Number(10000.45).toLocaleString("en-GB"); console.log(`- English format: ${englishFormat}`)
 /* StackOverflow snippet: console should overlap rendered HTML area */.as-console-wrapper { max-height: 100%;important: top; 0; }

Parse numbers according to locale

For point 2 there is no simple standard JavaScript API. However, you can use some implementations suggested in this StackOverflow question .

The one I am using here is from a Blog Post from Mike Bostock :

 class NumberParser { constructor(locale) { const parts = new Intl.NumberFormat(locale).formatToParts(12345.6); const numerals = [...new Intl.NumberFormat(locale, {useGrouping: false}).format(9876543210)].reverse(); const index = new Map(numerals.map((d, i) => [d, i])); this._group = new RegExp(`[${parts.find(d => d.type === "group").value}]`, "g"); this._decimal = new RegExp(`[${parts.find(d => d.type === "decimal").value}]`); this._numeral = new RegExp(`[${numerals.join("")}]`, "g"); this._index = d => index.get(d); } parse(string) { return (string = string.trim().replace(this._group, "").replace(this._decimal, ".").replace(this._numeral, this._index))? +string: NaN; } } const enteredNumber = "10,000.45"; // parse number using german locale console.log(new NumberParser("de-DE").parse(enteredNumber)); // parse number using british locale console.log(new NumberParser("en-GB").parse(enteredNumber));
 /* StackOverflow snippet: console should overlap rendered HTML area */.as-console-wrapper { max-height: 100%;important: top; 0; }

Determining locale

Assuming your calculator runs in the browser you could use navigator.languages and/ or navigator.language to determine a user's locale. You can of course also create a dropdown or something to let the user choose which locale to use.

 function getPreferredBrowserLocale(){ return navigator.languages? navigator.languages[0]: navigator.language; } console.log(getPreferredBrowserLocale())
 /* StackOverflow snippet: console should overlap rendered HTML area */.as-console-wrapper { max-height: 100%;important: top; 0; }

Putting it together

You can merge both those operations in one single class which you can easily instantiate using the the preferred locale.

 class NumberParser { constructor(locale) { const parts = new Intl.NumberFormat(locale).formatToParts(12345.6); const numerals = [...new Intl.NumberFormat(locale, {useGrouping: false}).format(9876543210)].reverse(); const index = new Map(numerals.map((d, i) => [d, i])); this._group = new RegExp(`[${parts.find(d => d.type === "group").value}]`, "g"); this._decimal = new RegExp(`[${parts.find(d => d.type === "decimal").value}]`); this._numeral = new RegExp(`[${numerals.join("")}]`, "g"); this._index = d => index.get(d); this._locale = locale; } format(number){ return new Intl.NumberFormat(this._locale).format(number); } parse(string) { return (string = string.trim().replace(this._group, "").replace(this._decimal, ".").replace(this._numeral, this._index))? +string: NaN; } } function getPreferredBrowserLocale(){ return navigator.languages? navigator.languages[0]: navigator.language; } const numberParser = new NumberParser(getPreferredBrowserLocale()); console.log(`Number in preferred locale: ${numberParser.format(10000.45)}`)
 /* StackOverflow snippet: console should overlap rendered HTML area */.as-console-wrapper { max-height: 100%;important: top; 0; }

Hopefully this will give you an idea on how to implement your calculator. Happy Coding:)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM