¿Cómo imprimir números con comas como separadores de miles?


754

Estoy tratando de imprimir un número entero en Python 2.6.1 con comas como miles de separadores. Por ejemplo, quiero mostrar el número 1234567como 1,234,567. ¿Cómo haría para hacer esto? He visto muchos ejemplos en Google, pero estoy buscando la forma práctica más simple.

No es necesario que sea específico de la localidad para decidir entre puntos y comas. Preferiría algo tan simple como sea razonablemente posible.

Respuestas:


1739

Configuración regional desconocida

'{:,}'.format(value)  # For Python ≥2.7
f'{value:,}'  # For Python ≥3.6

Locale consciente

import locale
locale.setlocale(locale.LC_ALL, '')  # Use '' for auto, or force e.g. to 'en_US.UTF-8'

'{:n}'.format(value)  # For Python ≥2.7
f'{value:n}'  # For Python ≥3.6

Referencia

Por formato de especificación Mini-idioma ,

La ','opción señala el uso de una coma para un separador de miles. Para un separador de configuración regional, use el 'n'tipo de presentación entero en su lugar.


25
Tenga en cuenta que esto no será correcto fuera de los EE. UU. Y en algunos otros lugares, en ese caso el locale.format () elegido es la respuesta correcta.
Gringo Suave

11
La forma de argumento de la palabra clave:{val:,}.format(val=val)
CivFan

11
Muchas gracias. Para cantidades de dinero, con 2 decimales - "{:,. 2f}". Formato (valor)
dlink

3
para Portugal, donde usamos el punto (.) como separador solo: {:,} ". format (value) .replace (',', '.')

13
En python 3.6 y versiones posteriores, las cadenas f agregan aún más comodidad. Ej .f"{2 ** 64 - 1:,}"
CJ Gaconnet el

285

Tengo esto para trabajar:

>>> import locale
>>> locale.setlocale(locale.LC_ALL, 'en_US')
'en_US'
>>> locale.format("%d", 1255000, grouping=True)
'1,255,000'

Claro, no necesita soporte de internacionalización, pero es claro, conciso y utiliza una biblioteca incorporada.

PD: "% d" es el formateador de estilo% habitual. Puede tener solo un formateador, pero puede ser lo que necesite en términos de ancho de campo y configuración de precisión.

PPS Si no puede ponerse localea trabajar, le sugiero una versión modificada de la respuesta de Mark:

def intWithCommas(x):
    if type(x) not in [type(0), type(0L)]:
        raise TypeError("Parameter must be an integer.")
    if x < 0:
        return '-' + intWithCommas(-x)
    result = ''
    while x >= 1000:
        x, r = divmod(x, 1000)
        result = ",%03d%s" % (r, result)
    return "%d%s" % (x, result)

La recursión es útil para el caso negativo, pero una recurrencia por coma me parece un poco excesiva.


14
Intenté su código, y desafortunadamente, obtengo esto: "locale.Error: configuración regional no compatible". : -s
Mark Byers el

11
Mark: Si está en Linux, es posible que desee ver lo que está en su /etc/locale.gen, o lo que sea que esté usando su glibc para construir sus configuraciones regionales. También es posible que desee probar "" en "," en_US.utf8 "," en_US.UTF-8 ", 'en_UK" (sp?), Etc. mikez: Debe haber un libro: "Dr. PEP: O Cómo aprendí a dejar de preocuparme y amar docs.python.org ". Dejé de memorizar todas las bibliotecas en Python 1.5.6. En cuanto a locale, uso lo menos que puedo.
Mike DeSimone

10
Puede usar '' para setlocaleusar el valor predeterminado, que con suerte será apropiado.
Mark Ransom el

24
Intente esto: locale.setlocale (locale.LC_ALL, '') Funcionó para mí
Nadia Alramli

1
Aunque inteligente, no me gustan las funciones que hacen configuraciones globales ... Usar 'blah'.format () es la mejor manera de hacerlo.
Cerin

132

Por ineficiencia e ilegibilidad es difícil de superar:

>>> import itertools
>>> s = '-1234567'
>>> ','.join(["%s%s%s" % (x[0], x[1] or '', x[2] or '') for x in itertools.izip_longest(s[::-1][::3], s[::-1][1::3], s[::-1][2::3])])[::-1].replace('-,','-')

171
Elegido como el método más ineficiente e ilegible para responder esta pregunta.
psytek

1
Sería bueno si esto al menos funcionara. pruebe este número "17371830" se convierte en "173.718.3.0" =)
holms

55
Períodos? Eso ni siquiera es posible, holms. Este pedazo de basura ignora totalmente la configuración regional. Me pregunto cómo obtuviste ese resultado. Su ejemplo produce '17, 371,830 'para mí, como se esperaba.
Kasey Kirkham

11
Para que esto sea una función, sugeriría: lambda x: (lambda s: ','.join(["%s%s%s" % (x[0], x[1] or '', x[2] or '') for x in itertools.izip_longest(s[::-1][::3], s[::-1][1::3], s[::-1][2::3])])[::-1].replace('-,','-'))(str(x))solo para mantener el tema de ofuscación.
Quantum

95

Aquí está el código de agrupación local después de eliminar partes irrelevantes y limpiarlo un poco:

(Lo siguiente solo funciona para enteros)

def group(number):
    s = '%d' % number
    groups = []
    while s and s[-1].isdigit():
        groups.append(s[-3:])
        s = s[:-3]
    return s + ','.join(reversed(groups))

>>> group(-23432432434.34)
'-23,432,432,434'

Ya hay algunas buenas respuestas aquí. Solo quiero agregar esto para referencia futura. En python 2.7 habrá un especificador de formato para el separador de miles. Según los documentos de Python , funciona así

>>> '{:20,.2f}'.format(f)
'18,446,744,073,709,551,616.00'

En python3.1 puedes hacer lo mismo así:

>>> format(1234567, ',d')
'1,234,567'

Sí, las formas más difíciles son principalmente para las personas en Pythons más antiguas, como las que se envían con RHEL y otras distribuciones de soporte a largo plazo.
Mike DeSimone

3
¿Cómo expresar esto con cadenas de formato? "%, d"% 1234567 no funciona
Frederic Bazin

93

Me sorprende que nadie haya mencionado que puedes hacer esto con cadenas f en Python 3.6 tan fácil como esto:

>>> num = 10000000
>>> print(f"{num:,}")
10,000,000

... donde la parte después de los dos puntos es el especificador de formato. La coma es el carácter separador que desea, por lo que f"{num:_}"utiliza guiones bajos en lugar de una coma.

Esto es equivalente a usar format(num, ",")para versiones anteriores de python 3.


Esto es más fácil que cualquiera de las respuestas más votadas y no requiere importaciones adicionales.
Z4-tier hace

39

Aquí hay un reemplazo de expresiones regulares de una línea:

re.sub("(\d)(?=(\d{3})+(?!\d))", r"\1,", "%d" % val)

Funciona solo para salidas inegrales:

import re
val = 1234567890
re.sub("(\d)(?=(\d{3})+(?!\d))", r"\1,", "%d" % val)
# Returns: '1,234,567,890'

val = 1234567890.1234567890
# Returns: '1,234,567,890'

O para flotantes con menos de 4 dígitos, cambie el especificador de formato a %.3f:

re.sub("(\d)(?=(\d{3})+(?!\d))", r"\1,", "%.3f" % val)
# Returns: '1,234,567,890.123'

Nota: no funciona correctamente con más de tres dígitos decimales, ya que intentará agrupar la parte decimal:

re.sub("(\d)(?=(\d{3})+(?!\d))", r"\1,", "%.5f" % val)
# Returns: '1,234,567,890.12,346'

Cómo funciona

Vamos a desglosarlo:

re.sub(pattern, repl, string)

pattern = \
    "(\d)           # Find one digit...
     (?=            # that is followed by...
         (\d{3})+   # one or more groups of three digits...
         (?!\d)     # which are not followed by any more digits.
     )",

repl = \
    r"\1,",         # Replace that one digit by itself, followed by a comma,
                    # and continue looking for more matches later in the string.
                    # (re.sub() replaces all matches it finds in the input)

string = \
    "%d" % val      # Format the string as a decimal to begin with

1
use el modo detallado y puede tener comentarios dentro del código
Daniel Stracaboško

¿No podría reemplazar el "(?! \ D)" con un "$"?
GL2014

28

Esto es lo que hago para las carrozas. Aunque, sinceramente, no estoy seguro de para qué versiones funciona, estoy usando 2.7:

my_number = 4385893.382939491

my_string = '{:0,.2f}'.format(my_number)

Devoluciones: 4,385,893.38

Actualización: Recientemente tuve un problema con este formato (no podía decirle la razón exacta), pero pude solucionarlo al soltar 0:

my_string = '{:,.2f}'.format(my_number)

19

También puede usarlo '{:n}'.format( value )para una representación regional. Creo que esta es la forma más sencilla para una solución local.

Para obtener más información, busque thousandsen Python DOC .

Para la moneda, puede usar locale.currency, estableciendo la bandera grouping:

Código

import locale

locale.setlocale( locale.LC_ALL, '' )
locale.currency( 1234567.89, grouping = True )

Salida

'Portuguese_Brazil.1252'
'R$ 1.234.567,89'

14

Ampliando ligeramente la respuesta de Ian Schneider:

Si desea utilizar un separador de miles personalizado, la solución más simple es:

'{:,}'.format(value).replace(',', your_custom_thousands_separator)

Ejemplos

'{:,.2f}'.format(123456789.012345).replace(',', ' ')

Si quieres una representación alemana como esta, se vuelve un poco más complicada:

('{:,.2f}'.format(123456789.012345)
          .replace(',', ' ')  # 'save' the thousands separators 
          .replace('.', ',')  # dot to comma
          .replace(' ', '.')) # thousand separators to dot

Un poco más corto:'{:_.2f}'.format(12345.6789).replace('.', ',').replace('_', '.')
Tom Pohl

12

Estoy seguro de que debe haber una función de biblioteca estándar para esto, pero fue divertido intentar escribirlo yo mismo usando la recursión, así que esto es lo que se me ocurrió:

def intToStringWithCommas(x):
    if type(x) is not int and type(x) is not long:
        raise TypeError("Not an integer!")
    if x < 0:
        return '-' + intToStringWithCommas(-x)
    elif x < 1000:
        return str(x)
    else:
        return intToStringWithCommas(x / 1000) + ',' + '%03d' % (x % 1000)

Habiendo dicho eso, si alguien más encuentra una forma estándar de hacerlo, debería usar eso en su lugar.


Lamentablemente no funciona en todos los casos. intToStringWithCommas (1000.1) -> '1.0001,000'
Nadia Alramli el

Específicamente dijo números enteros y que debería ser lo más simple posible, así que decidí no manejar tipos de datos que no sean enteros. También lo hice explícito en el nombre de la función _int_ToStringWithCommas. Ahora también he agregado un aumento para que quede más claro.
Mark Byers

8

De los comentarios a la receta activa del estado 498181, volví a trabajar esto:

import re
def thous(x, sep=',', dot='.'):
    num, _, frac = str(x).partition(dot)
    num = re.sub(r'(\d{3})(?=\d)', r'\1'+sep, num[::-1])[::-1]
    if frac:
        num += dot + frac
    return num

Utiliza la función de expresiones regulares: lookahead, es decir, (?=\d)para asegurarse de que solo los grupos de tres dígitos que tienen un dígito 'después' obtengan una coma. Digo 'después' porque la cadena es inversa en este punto.

[::-1] solo invierte una cadena.



7

Python 3

-

Enteros (sin decimal):

"{:,d}".format(1234567)

-

Flotadores (con decimal):

"{:,.2f}".format(1234567)

donde el número anterior fespecifica el número de decimales.

-

Prima

Función de arranque rápido y sucio para el sistema de numeración indio lakhs / crores (12,34,567):

https://stackoverflow.com/a/44832241/4928578


5

desde Python versión 2.6 puedes hacer esto:

def format_builtin(n):
    return format(n, ',')

Para las versiones de Python <2.6 y solo para su información, aquí hay 2 soluciones manuales, convierten los flotantes en ints pero los números negativos funcionan correctamente:

def format_number_using_lists(number):
    string = '%d' % number
    result_list = list(string)
    indexes = range(len(string))
    for index in indexes[::-3][1:]:
        if result_list[index] != '-':
            result_list.insert(index+1, ',')
    return ''.join(result_list)

Algunas cosas para notar aquí:

  • esta línea: string = '% d'% number convierte bellamente un número en una cadena, admite negativos y elimina fracciones de flotantes, convirtiéndolos en ints;
  • los índices de este segmento [:: - 3] devuelve cada tercer elemento comenzando desde el final, por lo que utilicé otro segmento [1:] para eliminar el último elemento porque no necesito una coma después del último número;
  • este condicional si l [index]! = '-' se está utilizando para admitir números negativos, no inserte una coma después del signo menos.

Y una versión más hardcore:

def format_number_using_generators_and_list_comprehensions(number):
    string = '%d' % number
    generator = reversed( 
        [
            value+',' if (index!=0 and value!='-' and index%3==0) else value
            for index,value in enumerate(reversed(string))
        ]
    )
    return ''.join(generator)

2

Soy un principiante de Python, pero un programador experimentado. Tengo Python 3.5, así que puedo usar la coma, pero este es un ejercicio de programación interesante. Considere el caso de un entero sin signo. El programa Python más legible para agregar miles de separadores parece ser:

def add_commas(instr):
    out = [instr[0]]
    for i in range(1, len(instr)):
        if (len(instr) - i) % 3 == 0:
            out.append(',')
        out.append(instr[i])
    return ''.join(out)

También es posible utilizar una lista de comprensión:

add_commas(instr):
    rng = reversed(range(1, len(instr) + (len(instr) - 1)//3 + 1))
    out = [',' if j%4 == 0 else instr[-(j - j//4)] for j in rng]
    return ''.join(out)

Esto es más corto, y podría ser de una sola línea, pero tendrás que hacer algo de gimnasia mental para entender por qué funciona. En ambos casos obtenemos:

for i in range(1, 11):
    instr = '1234567890'[:i]
    print(instr, add_commas(instr))
1 1
12 12
123 123
1234 1,234
12345 12,345
123456 123,456
1234567 1,234,567
12345678 12,345,678
123456789 123,456,789
1234567890 1,234,567,890

La primera versión es la opción más sensata, si desea que se entienda el programa.


1

Aquí hay uno que también funciona para carrozas:

def float2comma(f):
    s = str(abs(f)) # Convert to a string
    decimalposition = s.find(".") # Look for decimal point
    if decimalposition == -1:
        decimalposition = len(s) # If no decimal, then just work from the end
    out = "" 
    for i in range(decimalposition+1, len(s)): # do the decimal
        if not (i-decimalposition-1) % 3 and i-decimalposition-1: out = out+","
        out = out+s[i]      
    if len(out):
        out = "."+out # add the decimal point if necessary
    for i in range(decimalposition-1,-1,-1): # working backwards from decimal point
        if not (decimalposition-i-1) % 3 and decimalposition-i-1: out = ","+out
        out = s[i]+out      
    if f < 0:
        out = "-"+out
    return out

Ejemplo de uso:

>>> float2comma(10000.1111)
'10,000.111,1'
>>> float2comma(656565.122)
'656,565.122'
>>> float2comma(-656565.122)
'-656,565.122'

1
float2comma(12031023.1323)devuelve: '12, 031,023.132,3 '
demux

1

Un revestimiento para Python 2.5+ y Python 3 (solo int positivo):

''.join(reversed([x + (',' if i and not i % 3 else '') for i, x in enumerate(reversed(str(1234567)))]))

1

Solución universal

He encontrado algunos problemas con el separador de puntos en las respuestas más votadas anteriores. He diseñado una solución universal donde puedes usar lo que quieras como un separador de miles sin modificar la configuración regional . Sé que no es la solución más elegante, pero hace el trabajo. ¡Siéntete libre de mejorarlo!

def format_integer(number, thousand_separator='.'):
    def reverse(string):
        string = "".join(reversed(string))
        return string

    s = reverse(str(number))
    count = 0
    result = ''
    for char in s:
        count = count + 1
        if count % 3 == 0:
            if len(s) == count:
                result = char + result
            else:
                result = thousand_separator + char + result
        else:
            result = char + result
    return result


print(format_integer(50))
# 50
print(format_integer(500))
# 500
print(format_integer(50000))
# 50.000
print(format_integer(50000000))
# 50.000.000

0

Esto hace dinero junto con las comas

def format_money(money, presym='$', postsym=''):
    fmt = '%0.2f' % money
    dot = string.find(fmt, '.')
    ret = []
    if money < 0 :
        ret.append('(')
        p0 = 1
    else :
        p0 = 0
    ret.append(presym)
    p1 = (dot-p0) % 3 + p0
    while True :
        ret.append(fmt[p0:p1])
        if p1 == dot : break
        ret.append(',')
        p0 = p1
        p1 += 3
    ret.append(fmt[dot:])   # decimals
    ret.append(postsym)
    if money < 0 : ret.append(')')
    return ''.join(ret)

0

Tengo una versión de python 2 y python 3 de este código. Sé que la pregunta se hizo para Python 2, pero ahora (8 años después, jajaja) la gente probablemente usará Python 3.

Código Python 3:

import random
number = str(random.randint(1, 10000000))
comma_placement = 4
print('The original number is: {}. '.format(number))
while True:
    if len(number) % 3 == 0:
        for i in range(0, len(number) // 3 - 1):
            number = number[0:len(number) - comma_placement + 1] + ',' + number[len(number) - comma_placement + 1:]
            comma_placement = comma_placement + 4
    else:
        for i in range(0, len(number) // 3):
            number = number[0:len(number) - comma_placement + 1] + ',' + number[len(number) - comma_placement + 1:]
    break
print('The new and improved number is: {}'.format(number))        


Código de Python 2: (Editar. El código de Python 2 no funciona. Creo que la sintaxis es diferente).

import random
number = str(random.randint(1, 10000000))
comma_placement = 4
print 'The original number is: %s.' % (number)
while True:
    if len(number) % 3 == 0:
        for i in range(0, len(number) // 3 - 1):
            number = number[0:len(number) - comma_placement + 1] + ',' + number[len(number) - comma_placement + 1:]
            comma_placement = comma_placement + 4
    else:
        for i in range(0, len(number) // 3):
            number = number[0:len(number) - comma_placement + 1] + ',' + number[len(number) - comma_placement + 1:]
    break
print 'The new and improved number is: %s.' % (number) 

0

Estoy usando Python 2.5, así que no tengo acceso al formato incorporado.

Miré el código Django intcomma (intcomma_recurs en el código a continuación) y me di cuenta de que es ineficiente, porque es recursivo y también compilar la expresión regular en cada ejecución tampoco es algo bueno. Esto no es necesariamente un 'problema' ya que django no está realmente tan enfocado en este tipo de rendimiento de bajo nivel. Además, esperaba un factor de diferencia de 10 en el rendimiento, pero es solo 3 veces más lento.

Por curiosidad, implementé algunas versiones de intcomma para ver cuáles son las ventajas de rendimiento al usar regex. Los datos de mi prueba concluyen una ligera ventaja para esta tarea, pero sorprendentemente no mucho.

También me complació ver lo que sospechaba: el uso del enfoque de xrange inverso es innecesario en el caso de no regex, pero hace que el código se vea un poco mejor a un costo de ~ 10% de rendimiento.

Además, supongo que lo que está pasando es una cadena y se parece un poco a un número. Resultados indeterminados de otra manera.

from __future__ import with_statement
from contextlib import contextmanager
import re,time

re_first_num = re.compile(r"\d")
def intcomma_noregex(value):
    end_offset, start_digit, period = len(value),re_first_num.search(value).start(),value.rfind('.')
    if period == -1:
        period=end_offset
    segments,_from_index,leftover = [],0,(period-start_digit) % 3
    for _index in xrange(start_digit+3 if not leftover else start_digit+leftover,period,3):
        segments.append(value[_from_index:_index])
        _from_index=_index
    if not segments:
        return value
    segments.append(value[_from_index:])
    return ','.join(segments)

def intcomma_noregex_reversed(value):
    end_offset, start_digit, period = len(value),re_first_num.search(value).start(),value.rfind('.')
    if period == -1:
        period=end_offset
    _from_index,segments = end_offset,[]
    for _index in xrange(period-3,start_digit,-3):
        segments.append(value[_index:_from_index])
        _from_index=_index
    if not segments:
        return value
    segments.append(value[:_from_index])
    return ','.join(reversed(segments))

re_3digits = re.compile(r'(?<=\d)\d{3}(?!\d)')
def intcomma(value):
    segments,last_endoffset=[],len(value)
    while last_endoffset > 3:
        digit_group = re_3digits.search(value,0,last_endoffset)
        if not digit_group:
            break
        segments.append(value[digit_group.start():last_endoffset])
        last_endoffset=digit_group.start()
    if not segments:
        return value
    if last_endoffset:
        segments.append(value[:last_endoffset])
    return ','.join(reversed(segments))

def intcomma_recurs(value):
    """
    Converts an integer to a string containing commas every three digits.
    For example, 3000 becomes '3,000' and 45000 becomes '45,000'.
    """
    new = re.sub("^(-?\d+)(\d{3})", '\g<1>,\g<2>', str(value))
    if value == new:
        return new
    else:
        return intcomma(new)

@contextmanager
def timed(save_time_func):
    begin=time.time()
    try:
        yield
    finally:
        save_time_func(time.time()-begin)

def testset_xsimple(func):
    func('5')

def testset_simple(func):
    func('567')

def testset_onecomma(func):
    func('567890')

def testset_complex(func):
    func('-1234567.024')

def testset_average(func):
    func('-1234567.024')
    func('567')
    func('5674')

if __name__ == '__main__':
    print 'Test results:'
    for test_data in ('5','567','1234','1234.56','-253892.045'):
        for func in (intcomma,intcomma_noregex,intcomma_noregex_reversed,intcomma_recurs):
            print func.__name__,test_data,func(test_data)
    times=[]
    def overhead(x):
        pass
    for test_run in xrange(1,4):
        for func in (intcomma,intcomma_noregex,intcomma_noregex_reversed,intcomma_recurs,overhead):
            for testset in (testset_xsimple,testset_simple,testset_onecomma,testset_complex,testset_average):
                for x in xrange(1000): # prime the test
                    testset(func)
                with timed(lambda x:times.append(((test_run,func,testset),x))):
                    for x in xrange(50000):
                        testset(func)
    for (test_run,func,testset),_delta in times:
        print test_run,func.__name__,testset.__name__,_delta

Y aquí están los resultados de la prueba:

intcomma 5 5
intcomma_noregex 5 5
intcomma_noregex_reversed 5 5
intcomma_recurs 5 5
intcomma 567 567
intcomma_noregex 567 567
intcomma_noregex_reversed 567 567
intcomma_recurs 567 567
intcomma 1234 1,234
intcomma_noregex 1234 1,234
intcomma_noregex_reversed 1234 1,234
intcomma_recurs 1234 1,234
intcomma 1234.56 1,234.56
intcomma_noregex 1234.56 1,234.56
intcomma_noregex_reversed 1234.56 1,234.56
intcomma_recurs 1234.56 1,234.56
intcomma -253892.045 -253,892.045
intcomma_noregex -253892.045 -253,892.045
intcomma_noregex_reversed -253892.045 -253,892.045
intcomma_recurs -253892.045 -253,892.045
1 intcomma testset_xsimple 0.0410001277924
1 intcomma testset_simple 0.0369999408722
1 intcomma testset_onecomma 0.213000059128
1 intcomma testset_complex 0.296000003815
1 intcomma testset_average 0.503000020981
1 intcomma_noregex testset_xsimple 0.134000062943
1 intcomma_noregex testset_simple 0.134999990463
1 intcomma_noregex testset_onecomma 0.190999984741
1 intcomma_noregex testset_complex 0.209000110626
1 intcomma_noregex testset_average 0.513000011444
1 intcomma_noregex_reversed testset_xsimple 0.124000072479
1 intcomma_noregex_reversed testset_simple 0.12700009346
1 intcomma_noregex_reversed testset_onecomma 0.230000019073
1 intcomma_noregex_reversed testset_complex 0.236999988556
1 intcomma_noregex_reversed testset_average 0.56299996376
1 intcomma_recurs testset_xsimple 0.348000049591
1 intcomma_recurs testset_simple 0.34600019455
1 intcomma_recurs testset_onecomma 0.625
1 intcomma_recurs testset_complex 0.773999929428
1 intcomma_recurs testset_average 1.6890001297
1 overhead testset_xsimple 0.0179998874664
1 overhead testset_simple 0.0190000534058
1 overhead testset_onecomma 0.0190000534058
1 overhead testset_complex 0.0190000534058
1 overhead testset_average 0.0309998989105
2 intcomma testset_xsimple 0.0360000133514
2 intcomma testset_simple 0.0369999408722
2 intcomma testset_onecomma 0.207999944687
2 intcomma testset_complex 0.302000045776
2 intcomma testset_average 0.523000001907
2 intcomma_noregex testset_xsimple 0.139999866486
2 intcomma_noregex testset_simple 0.141000032425
2 intcomma_noregex testset_onecomma 0.203999996185
2 intcomma_noregex testset_complex 0.200999975204
2 intcomma_noregex testset_average 0.523000001907
2 intcomma_noregex_reversed testset_xsimple 0.130000114441
2 intcomma_noregex_reversed testset_simple 0.129999876022
2 intcomma_noregex_reversed testset_onecomma 0.236000061035
2 intcomma_noregex_reversed testset_complex 0.241999864578
2 intcomma_noregex_reversed testset_average 0.582999944687
2 intcomma_recurs testset_xsimple 0.351000070572
2 intcomma_recurs testset_simple 0.352999925613
2 intcomma_recurs testset_onecomma 0.648999929428
2 intcomma_recurs testset_complex 0.808000087738
2 intcomma_recurs testset_average 1.81900000572
2 overhead testset_xsimple 0.0189998149872
2 overhead testset_simple 0.0189998149872
2 overhead testset_onecomma 0.0190000534058
2 overhead testset_complex 0.0179998874664
2 overhead testset_average 0.0299999713898
3 intcomma testset_xsimple 0.0360000133514
3 intcomma testset_simple 0.0360000133514
3 intcomma testset_onecomma 0.210000038147
3 intcomma testset_complex 0.305999994278
3 intcomma testset_average 0.493000030518
3 intcomma_noregex testset_xsimple 0.131999969482
3 intcomma_noregex testset_simple 0.136000156403
3 intcomma_noregex testset_onecomma 0.192999839783
3 intcomma_noregex testset_complex 0.202000141144
3 intcomma_noregex testset_average 0.509999990463
3 intcomma_noregex_reversed testset_xsimple 0.125999927521
3 intcomma_noregex_reversed testset_simple 0.126999855042
3 intcomma_noregex_reversed testset_onecomma 0.235999822617
3 intcomma_noregex_reversed testset_complex 0.243000030518
3 intcomma_noregex_reversed testset_average 0.56200003624
3 intcomma_recurs testset_xsimple 0.337000131607
3 intcomma_recurs testset_simple 0.342000007629
3 intcomma_recurs testset_onecomma 0.609999895096
3 intcomma_recurs testset_complex 0.75
3 intcomma_recurs testset_average 1.68300008774
3 overhead testset_xsimple 0.0189998149872
3 overhead testset_simple 0.018000125885
3 overhead testset_onecomma 0.018000125885
3 overhead testset_complex 0.0179998874664
3 overhead testset_average 0.0299999713898

Pensé que la solución de una sola expresión regular de Daniel Fortunov sería la n. ° 1 y superaría todos los algoritmos porque la expresión regular es muy refinada / optimizada y codificada en C, pero no ... Supongo que el patrón y la búsqueda anticipada son demasiado caros. cae aproximadamente el doble del tiempo de la intcomma anterior, incluso con la precompilación de la expresión regular.
parity3


-1

Aquí hay otra variante que usa una función de generador que funciona para enteros:

def ncomma(num):
    def _helper(num):
        # assert isinstance(numstr, basestring)
        numstr = '%d' % num
        for ii, digit in enumerate(reversed(numstr)):
            if ii and ii % 3 == 0 and digit.isdigit():
                yield ','
            yield digit

    return ''.join(reversed([n for n in _helper(num)]))

Y aquí hay una prueba:

>>> for i in (0, 99, 999, 9999, 999999, 1000000, -1, -111, -1111, -111111, -1000000):
...     print i, ncomma(i)
... 
0 0
99 99
999 999
9999 9,999
999999 999,999
1000000 1,000,000
-1 -1
-111 -111
-1111 -1,111
-111111 -111,111
-1000000 -1,000,000

-1

Solo subclase long(o float, o lo que sea). Esto es muy práctico, porque de esta manera todavía puede usar sus números en operaciones matemáticas (y, por lo tanto, el código existente), pero todos se imprimirán bien en su terminal.

>>> class number(long):

        def __init__(self, value):
            self = value

        def __repr__(self):
            s = str(self)
            l = [x for x in s if x in '1234567890']
            for x in reversed(range(len(s)-1)[::3]):
                l.insert(-x, ',')
            l = ''.join(l[1:])
            return ('-'+l if self < 0 else l) 

>>> number(-100000)
-100,000
>>> number(-100)
-100
>>> number(-12345)
-12,345
>>> number(928374)
928,374
>>> 345

8
Me gusta la idea de la subclase, pero ¿es __repr__()el método correcto para anular? Sugeriría anular __str__()y dejar __repr__()solo, porque int(repr(number(928374)))debería funcionar, pero int()se ahogará con las comas.
steveha 01 de

@steveha tiene un buen punto, pero la justificación debería haber sido que number(repr(number(928374)))no funciona, no int(repr(number(928374))). De todos modos, para hacer que este enfoque funcione directamente print, como lo solicitó el OP, el __str__()método debería ser el anulado en lugar de hacerlo __repr__(). En cualquier caso, parece haber un error en la lógica de inserción de comas principales.
Martineau

-1

Italia:

>>> import locale
>>> locale.setlocale(locale.LC_ALL,"")
'Italian_Italy.1252'
>>> f"{1000:n}"
'1.000'

-8

Para carrozas:

float(filter(lambda x: x!=',', '1,234.52'))
# returns 1234.52

Para entradas:

int(filter(lambda x: x!=',', '1,234'))
# returns 1234

55
Eso elimina las comas. Aunque útil, el OP solicitó una forma de agregarlos . Además, algo así float('1,234.52'.translate(None, ','))podría ser más sencillo y posiblemente más rápido.
Pausado hasta nuevo aviso.
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.