Insertar comas en la cadena de números

Hola, bash realizar una búsqueda de expresiones regulares hacia atrás en una cadena para dividirla en grupos de 3 dígitos. Por lo que puedo ver en la documentación de AS3, la búsqueda hacia atrás no es posible en el motor de registro.

El objective de este ejercicio es insertar comillas triples en un número como este:

10000000 => 10,000,000 

Estoy pensando en hacerlo así:

 string.replace(/(\d{3})/g, ",$1") 

Pero esto no es correcto debido a que la búsqueda no ocurre desde atrás y el reemplazo de $ 1 solo funcionará para la primera coincidencia.

Tengo la sensación de que sería mejor que realice esta tarea utilizando un ciclo.

ACTUALIZAR:

Debido a que AS3 no admite búsquedas anticipadas, así es como lo he resuelto.

 public static function formatNumber(number:Number):String { var numString:String = number.toString() var result:String = '' while (numString.length > 3) { var chunk:String = numString.substr(-3) numString = numString.substr(0, numString.length - 3) result = ',' + chunk + result } if (numString.length > 0) { result = numString + result } return result } 

Si su lenguaje admite afirmaciones de búsqueda anticipada, entonces creo que la siguiente expresión regular funcionará:

 (\d)(?=(\d{3})+$) 

Demostrado en Java:

 import static org.junit.Assert.assertEquals; import org.junit.Test; public class CommifyTest { @Test public void testCommify() { String num0 = "1"; String num1 = "123456"; String num2 = "1234567"; String num3 = "12345678"; String num4 = "123456789"; String regex = "(\\d)(?=(\\d{3})+$)"; assertEquals("1", num0.replaceAll(regex, "$1,")); assertEquals("123,456", num1.replaceAll(regex, "$1,")); assertEquals("1,234,567", num2.replaceAll(regex, "$1,")); assertEquals("12,345,678", num3.replaceAll(regex, "$1,")); assertEquals("123,456,789", num4.replaceAll(regex, "$1,")); } } 

El siguiente enlace sugiere que AS3 lo hace?

Encontrado en http://gskinner.com/RegExr/

Comunidad> Separador de miles

Patrón: /\d{1,3}(?=(\d{3})+(?!\d))/g

Reemplazar: $&,

 trace ( String("1000000000").replace( /\d{1,3}(?=(\d{3})+(?!\d))/g , "$&,") ); 

¡Hizo el trabajo!

Si su motor regex tiene un lookaheads positivo, podría hacer algo como esto:

 string.replace(/(\d)(?=(\d\d\d)+$)/, "$1,") 

Donde la anticipación positiva (? = …) significa que la expresión regular solo coincide cuando la expresión de búsqueda anticipada … coincide.

(Tenga en cuenta que las expresiones alternativas no siempre son muy eficientes).

Si bien muchas de estas respuestas funcionan bien con números enteros positivos, muchas de sus entradas de argumento se expresan como números, lo que implica que pueden manejar valores negativos o contener decimales, y aquí todas las soluciones fallan. Aunque la respuesta seleccionada actualmente no supone un número, sentí curiosidad por encontrar una solución que pudiera y fuera también más eficaz que RegExp (que AS3 no funciona bien).

Reuní muchas de las respuestas aquí en una clase de prueba (e incluí una solución de este blog y una respuesta de mi propia llamada llamada commaify ) y las formateé de forma consistente para facilitar la comparación:

 package { public class CommaNumberSolutions { public static function commaify( input:Number ):String { var split:Array = input.toString().split( '.' ), front:String = split[0], back:String = ( split.length > 1 ) ? "." + split[1] : null, n:int = input < 0 ? 2 : 1, commas:int = Math.floor( (front.length - n) / 3 ), i:int = 1; for ( ; i <= commas; i++ ) { n = front.length - (3 * i + i - 1); front = front.slice( 0, n ) + "," + front.slice( n ); } if ( back ) return front + back; else return front; } public static function getCommaString( input:Number ):String { var s:String = input.toString(); if ( s.length <= 3 ) return s; var i:int = s.length % 3; if ( i == 0 ) i = 3; for ( ; i < s.length; i += 4 ) { var part1:String = s.substr(0, i); var part2:String = s.substr(i, s.length); s = part1.concat(",", part2); } return s; } public static function formatNumber( input:Number ):String { var s:String = input.toString() var result:String = '' while ( s.length > 3 ) { var chunk:String = s.substr(-3) s = s.substr(0, s.length - 3) result = ',' + chunk + result } if ( s.length > 0 ) result = s + result return result } public static function commaCoder( input:Number ):String { var s:String = ""; var len:Number = input.toString().length; for ( var i:int = 0; i < len; i++ ) { if ( (len-i) % 3 == 0 && i != 0) s += ","; s += input.toString().charAt(i); } return s; } public static function regex1( input:Number ):String { return input.toString().replace( /-{0,1}(\d)(?=(\d\d\d)+$)/g, "$1," ); } public static function regex2( input:Number ):String { return input.toString().replace( /-{0,1}\d{1,3}(?=(\d{3})+(?!\d))/g , "$&,") } public static function addCommas( input:Number ):String { var negative:String = ""; if ( input < 0 ) { negative = "-"; input = Math.abs(input); } var s:String = input.toString(); var results:Array = s.split(/\./); s = results[0]; if ( s.length > 3 ) { var mod:Number = s.length % 3; var output:String = s.substr(0, mod); for ( var i:Number = mod; i < s.length; i += 3 ) { output += ((mod == 0 && i == 0) ? "" : ",") + s.substr(i, 3); } if ( results.length > 1 ) { if ( results[1].length == 1 ) return negative + output + "." + results[1] + "0"; else return negative + output + "." + results[1]; } else return negative + output; } if ( results.length > 1 ) { if ( results[1].length == 1 ) return negative + s + "." + results[1] + "0"; else return negative + s + "." + results[1]; } else return negative + s; } } } 

Luego probé cada uno para la precisión y el rendimiento:

 package { public class TestCommaNumberSolutions { private var functions:Array; function TestCommaNumberSolutions() { functions = [ { name: "commaify()", f: CommaNumberSolutions.commaify }, { name: "addCommas()", f: CommaNumberSolutions.addCommas }, { name: "getCommaString()", f: CommaNumberSolutions.getCommaString }, { name: "formatNumber()", f: CommaNumberSolutions.formatNumber }, { name: "regex1()", f: CommaNumberSolutions.regex1 }, { name: "regex2()", f: CommaNumberSolutions.regex2 }, { name: "commaCoder()", f: CommaNumberSolutions.commaCoder } ]; verify(); measure(); } protected function verify():void { var assertions:Array = [ { input: 1, output: "1" }, { input: 21, output: "21" }, { input: 321, output: "321" }, { input: 4321, output: "4,321" }, { input: 54321, output: "54,321" }, { input: 654321, output: "654,321" }, { input: 7654321, output: "7,654,321" }, { input: 987654321, output: "987,654,321" }, { input: 1987654321, output: "1,987,654,321" }, { input: 21987654321, output: "21,987,654,321" }, { input: 321987654321, output: "321,987,654,321" }, { input: 4321987654321, output: "4,321,987,654,321" }, { input: 54321987654321, output: "54,321,987,654,321" }, { input: 654321987654321, output: "654,321,987,654,321" }, { input: 7654321987654321, output: "7,654,321,987,654,321" }, { input: 87654321987654321, output: "87,654,321,987,654,321" }, { input: -1, output: "-1" }, { input: -21, output: "-21" }, { input: -321, output: "-321" }, { input: -4321, output: "-4,321" }, { input: -54321, output: "-54,321" }, { input: -654321, output: "-654,321" }, { input: -7654321, output: "-7,654,321" }, { input: -987654321, output: "-987,654,321" }, { input: -1987654321, output: "-1,987,654,321" }, { input: -21987654321, output: "-21,987,654,321" }, { input: -321987654321, output: "-321,987,654,321" }, { input: -4321987654321, output: "-4,321,987,654,321" }, { input: -54321987654321, output: "-54,321,987,654,321" }, { input: -654321987654321, output: "-654,321,987,654,321" }, { input: -7654321987654321, output: "-7,654,321,987,654,321" }, { input: -87654321987654321, output: "-87,654,321,987,654,321" }, { input: .012345, output: "0.012345" }, { input: 1.012345, output: "1.012345" }, { input: 21.012345, output: "21.012345" }, { input: 321.012345, output: "321.012345" }, { input: 4321.012345, output: "4,321.012345" }, { input: 54321.012345, output: "54,321.012345" }, { input: 654321.012345, output: "654,321.012345" }, { input: 7654321.012345, output: "7,654,321.012345" }, { input: 987654321.012345, output: "987,654,321.012345" }, { input: 1987654321.012345, output: "1,987,654,321.012345" }, { input: 21987654321.012345, output: "21,987,654,321.012345" }, { input: -.012345, output: "-0.012345" }, { input: -1.012345, output: "-1.012345" }, { input: -21.012345, output: "-21.012345" }, { input: -321.012345, output: "-321.012345" }, { input: -4321.012345, output: "-4,321.012345" }, { input: -54321.012345, output: "-54,321.012345" }, { input: -654321.012345, output: "-654,321.012345" }, { input: -7654321.012345, output: "-7,654,321.012345" }, { input: -987654321.012345, output: "-987,654,321.012345" }, { input: -1987654321.012345, output: "-1,987,654,321.012345" }, { input: -21987654321.012345, output: "-21,987,654,321.012345" } ]; var i:int; var len:int = assertions.length; var assertion:Object; var f:Function; var s1:String; var s2:String; for each ( var o:Object in functions ) { i = 0; f = of; trace( '\rVerify: ' + o.name ); for ( ; i < len; i++ ) { assertion = assertions[ i ]; s1 = f.apply( null, [ assertion.input ] ); s2 = assertion.output; if ( s1 !== s2 ) trace( 'Test #' + i + ' Failed: ' + s1 + ' !== ' + s2 ); } } } protected function measure():void { // Generate random inputs var values:Array = []; for ( var i:int = 0; i < 999999; i++ ) { values.push( Math.random() * int.MAX_VALUE * ( Math.random() > .5 ? -1 : 1) ); } var len:int = values.length; var stopwatch:Stopwatch = new Stopwatch; var s:String; var f:Function; trace( '\rTesting ' + len + ' random values' ); // Test each function for each ( var o:Object in functions ) { i = 0; s = ""; f = of; stopwatch.start(); for ( ; i < len; i++ ) { s += f.apply( null, [ values[i] ] ) + " "; } stopwatch.stop(); trace( o.name + '\t\ttook ' + (stopwatch.elapsed/1000) + 's' ); //(stopwatch.elapsed/len) + 'ms' } } } } import flash.utils.getTimer; class Stopwatch { protected var startStamp:int; protected var stopStamp:int; protected var _started:Boolean; protected var _stopped:Boolean; function Stopwatch( startNow:Boolean = true ):void { if ( startNow ) start(); } public function start():void { startStamp = getTimer(); _started = true; _stopped = false; } public function stop():void { stopStamp = getTimer(); _stopped = true; _started = false; } public function get elapsed():int { return ( _stopped ) ? stopStamp - startStamp : ( _started ) ? getTimer() - startStamp : 0; } public function get started():Boolean { return _started; } public function get stopped():Boolean { return _stopped; } } 

Debido a la falta de precisión de AS3 con números más grandes, cada clase falló estas pruebas:

 Test #15 Failed: 87,654,321,987,654,320 !== 87,654,321,987,654,321 Test #31 Failed: -87,654,321,987,654,320 !== -87,654,321,987,654,321 Test #42 Failed: 21,987,654,321.012344 !== 21,987,654,321.012345 Test #53 Failed: -21,987,654,321.012344 !== -21,987,654,321.012345 

Pero solo dos funciones pasaron todas las otras pruebas: commaify () y addCommas () .

Las pruebas de rendimiento muestran que commaify () es la más eficaz de todas las soluciones:

 Testing 999999 random values commaify() took 12.411s addCommas() took 17.863s getCommaString() took 18.519s formatNumber() took 14.409s regex1() took 40.654s regex2() took 36.985s 

Además, commaify () se puede extender para incluir argumentos para la longitud decimal y el relleno cero en la parte decimal; también supera a los demás en 13.128s :

 public static function cappedDecimal( input:Number, decimalPlaces:int = 2 ):Number { if ( decimalPlaces == 0 ) return Math.floor( input ); var decimalFactor:Number = Math.pow( 10, decimalPlaces ); return Math.floor( input * decimalFactor ) / decimalFactor; } public static function cappedDecimalString( input:Number, decimalPlaces:int = 2, padZeros:Boolean = true ):String { if ( padZeros ) return cappedDecimal( input, decimalPlaces ).toFixed( decimalPlaces ); else return cappedDecimal( input, decimalPlaces ).toString(); } public static function commaifyExtended( input:Number, decimalPlaces:int = 2, padZeros:Boolean = true ):String { var split:Array = cappedDecimalString( input, decimalPlaces, padZeros ).split( '.' ), front:String = split[0], back:String = ( split.length > 1 ) ? "." + split[1] : null, n:int = input < 0 ? 2 : 1, commas:int = Math.floor( (front.length - n) / 3 ), i:int = 1; for ( ; i <= commas; i++ ) { n = front.length - (3 * i + i - 1); front = front.slice( 0, n ) + "," + front.slice( n ); } if ( back ) return front + back; else return front; } 

Por lo tanto, ofrezco que commaify () cumple con las exigencias de versatilidad y rendimiento, aunque ciertamente no es el más compacto o elegante.

Este realmente no es el mejor uso de RegEx … No conozco una función de formateo de números, pero este hilo parece proporcionar una solución.

 function commaCoder(yourNum):String { //var yourNum:Number = new Number(); var numtoString:String = new String(); var numLength:Number = yourNum.toString().length; numtoString = ""; for (i=0; i 

Si realmente insiste en usar RegEx, podría simplemente invertir la cadena, aplicar la función Reemplazar RegEx y luego invertirla nuevamente.

Un sexeger es bueno para esto. En resumen, un sexeger es una corrida regex inversa contra una cadena invertida a la que invierte la salida. En general, es más eficiente que la alternativa. Aquí hay un pseudocódigo para lo que quiere hacer:

 string = reverse string string.replace(/(\d{3})(?!$)/g, "$1,") string = reverse string 

Aquí hay una implementación de Perl

 #!/usr/bin/perl use strict; use warnings; my $s = 13_456_789; for my $n (1, 12, 123, 1234, 12345, 123456, 1234567) { my $s = reverse $n; $s =~ s/([0-9]{3})(?!$)/$1,/g; $s = reverse $s; print "$s\n"; } 

Es posible que desee considerar NumberFormatter

// Este es un código simple y funciona bien … 🙂

 import java.util.Scanner; public class NumberWithCommas { public static void main(String a[]) { Scanner sc = new Scanner(System.in); String num; System.out.println("\n enter the number:"); num = sc.next(); printNumber(num); } public static void printNumber(String ar) { int len, i = 0, temp = 0; len = ar.length(); temp = len / 3; if (len % 3 == 0) temp = temp - 1; len = len + temp; char[] ch = ar.toCharArray(); char[] ch1 = new char[len]; for (int j = 0, k = (ar.length() - 1); j < len; j++) { if (i < 3) { ch1[j] = ch[k]; i++; k--; } else { ch1[j] = ','; i = 0; } } for (int j = len - 1; j >= 0; j--) System.out.print(ch1[j]); System.out.println(""); } } 

Si no puede usar anticipación en expresiones regulares, puede usar esto:

 string.replace(/^(.*?,)?(\d{1,3})((?:\d{3})+)$/, "$1$2,$3") 

dentro de un bucle hasta que no haya nada que reemplazar.

Por ejemplo, una solución perlish se vería así:

 my $num = '1234567890'; while ($num =~ s/^(.*?,)?(\d{1,3})((?:\d{3})+)$/$1$2,$3/) {} 

Prueba este código es simple y el mejor rendimiento.

 var reg:RegExp=/\d{1,3}(?=(\d{3})+(?!\d))/g; var my_num:Number = 48712694; var my_num_str:String = String(my_num).replace(reg,"$&,"); trace(my_num_str); 

::salida::

 48,712,694