Recientemente se me ocurrió este código mientras respondía otra pregunta de StackOverflow. Básicamente, en el desenfoque, este código se separará correctamente por comas por miles y dejará el decimal en dos dígitos (como se escribe USD [7,745.56]).
Me preguntaba si hay una forma más concisa de usar expresiones regulares para separar y cortar los lugares decimales excesivos. Recientemente actualicé esta publicación con mi intento más reciente. ¿Hay una mejor manera de hacer esto con expresiones regulares?
7456 -> 7,456 45345 -> 45,345 25.23523534 -> 25.23 3333.239 -> 3,333.23 234.99 -> 234.99 2300.99 -> 2,300.99 23123123123.22 -> 23,123,123,123.22 var result; var str = [] reg = new RegExp(/(\d*(\d{2}\.)|\d{1,3})/, "gi"); reversed = "9515321312.2323432".split("").reverse().join("") while (result = reg.exec(reversed)) { str.push(result[2] ? result[2] : result[0]) } console.log(str.join(",").split("").reverse().join("").replace(",.","."))Como alternativa a Regex, puede usar el siguiente enfoque
Number(num.toFixed(2)).toLocaleString('en-US')o
num.toLocaleString('en-US', {maximumFractionDigits: 2}) Todavía tendría toFixed(2) , pero está bastante limpio. toFixed(2) aunque no bajará el número como usted quiere. Lo mismo con {maximumFractionDigits: 2} como el segundo parámetro para toLocaleString también.
var nums = [7456, 45345, 25.23523534, 3333.239, 234.99, 2300.99, 23123123123.22] for (var num of nums) console.log(num, '->', Number(num.toFixed(2)).toLocaleString('en-US') ) Pisotear el número como mostraste es un poco complicado. Hacer algo como (num * 100 | 0) / 100 no funciona. El cálculo pierde precisión (por ejemplo, .99 se convertirá en .98 en ciertas situaciones). (también |0 no funcionaría con números más grandes, pero incluso Math.floor() tiene el problema de precisión).
La solución sería tratar los números como cadenas.
function format(num) { var num = num.toLocaleString('en-US') var end = num.indexOf('.') < 0 ? num.length : num.indexOf('.') + 3 return num.substring(0, end) } var nums = [7456, 45345, 25.23523534, 3333.239, 234.99, 2300.99, 23123123123.22] for (var num of nums) console.log(num, '->', format(num)) function format(num) { var num = num.toLocaleString('en-US') var end = num.indexOf('.') < 0 ? num.length : num.indexOf('.') + 3 return num.substring(0, end) } (al cambiar a otro formato que no sea 'en-US' preste atención al . en números, ya que algunos idiomas usan un , como separador de fractales)
Para compatibilidad , según CanIUse toLocaleString('en-US') es
compatible con todos los navegadores (desde IE6+, Firefox 2+, Chrome 1+, etc.)
Si realmente insiste en hacer esto puramente en expresiones regulares (y trunca en lugar de redondear los dígitos fraccionarios), la única solución que se me ocurre es usar una función de reemplazo como segundo argumento para .replace() :
('' + num).replace( /(\d)(?=(?:\d{3})+(?:\.|$))|(\.\d\d?)\d*$/g, function(m, s1, s2){ return s2 || (s1 + ','); } );Esto hace que todos sus casos de prueba pasen:
function format(num){ return ('' + num).replace( /(\d)(?=(?:\d{3})+(?:\.|$))|(\.\d\d?)\d*$/g, function(m, s1, s2){ return s2 || (s1 + ','); } ); } test(7456, "7,456"); test(45345, "45,345"); test(25.23523534, "25.23"); //truncated, not rounded test(3333.239, "3,333.23"); //truncated, not rounded test(234.99, "234.99"); test(2300.99, "2,300.99"); test(23123123123.22, "23,123,123,123.22"); function test(num, expected){ var actual = format(num); console.log(num + ' -> ' + expected + ' => ' + actual + ': ' + (actual === expected ? 'passed' : 'failed') ); }Probar:
var n = 5812090285.2817481974897; n = n.toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,'); console.log(n);Salidas:
5,812,090,285.28 Nota: .toFixed(2) devuelve una string . Entonces, para simplificar esto aún más, debe agregar una forma de convertir n en una string antes de ejecutar su expresión regular. Por ejemplo:
n.toString.replace(/(\d)(?=(\d{3})+\.)/g, '$1,'); //ofc with the additional regexAunque pensarías que no importaría en javascript, aparentemente lo hace en esta situación. Así que no sé cuánto 'menos' desordenado sería no usarlo.