Come stampare il numero con virgole come migliaia di separatori?


754

Sto cercando di stampare un numero intero in Python 2.6.1 con virgole come migliaia di separatori. Ad esempio, voglio mostrare il numero 1234567come 1,234,567. Come potrei fare per fare questo? Ho visto molti esempi su Google, ma sto cercando il modo pratico più semplice.

Non è necessario essere specifici delle impostazioni internazionali per decidere tra punti e virgole. Preferirei qualcosa di semplice quanto ragionevolmente possibile.

Risposte:


1739

Locale ignaro

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

Conoscenza delle impostazioni locali

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

Riferimento

Mini lingua specifica per formato ,

L' ','opzione segnala l'uso di una virgola per un separatore delle migliaia. Per un separatore con riconoscimento locale, utilizzare 'n'invece il tipo di presentazione intero.


25
Nota che questo non sarà corretto al di fuori degli Stati Uniti e in pochi altri luoghi, in quel caso il locale.format () scelto è la risposta corretta.
Gringo Suave,

11
La forma dell'argomento della parola chiave:{val:,}.format(val=val)
CivFan,

11
Grazie mille. Per importi in denaro, con 2 decimali - formato "{:,. 2f}". (Valore)
dlink

3
per il Portogallo, dove utilizziamo il punto (.) come separatore solo: {:,} ". format (valore) .replace (',', '.')

13
In python 3.6 e versioni successive, le stringhe f aggiungono ancora più praticità. Ad esempiof"{2 ** 64 - 1:,}"
CJ Gaconnet,

285

Ho ottenuto questo per funzionare:

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

Certo, non è necessario il supporto per l'internazionalizzazione, ma è chiaro, conciso e utilizza una libreria integrata.

PS Che "% d" è il solito formattatore in stile%. Puoi avere un solo formattatore, ma può essere quello che ti serve in termini di larghezza del campo e impostazioni di precisione.

PPS Se non riesci localea lavorare, suggerirei una versione modificata della risposta di 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 ricorsione è utile per il caso negativo, ma una ricorsione per virgola mi sembra un po 'eccessiva.


14
Ho provato il tuo codice e sfortunatamente ottengo questo: "locale.Error: impostazione locale non supportata". : -s
Mark Byers,

11
Mark: Se sei su Linux, potresti voler guardare cosa c'è in /etc/locale.gen, o qualunque cosa il tuo glibc stia usando per costruire le sue localizzazioni. Potresti anche provare "" en "," en_US.utf8 "," en_US.UTF-8 ", 'en_UK" (sp?), Ecc. Mikez: Deve esserci un libro: "Dr. PEP: Or Come ho imparato a smettere di preoccuparmi e amare docs.python.org. " Ho rinunciato a memorizzare tutte le librerie attorno a Python 1.5.6. Per quanto riguarda locale, ne uso il meno possibile.
Mike DeSimone,

10
Puoi usare '' per setlocaleusare il valore predefinito, che si spera sia appropriato.
Mark Ransom,

24
Prova questo: locale.setlocale (locale.LC_ALL, '') Ha funzionato per me
Nadia Alramli,

1
Anche se intelligente, non mi piacciono le funzioni che rendono le impostazioni globali ... L'uso di 'blah'.format () è il modo migliore di procedere.
Cerin

132

Per inefficienza e illeggibilità è difficile da battere:

>>> 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
Votato per il metodo più inefficiente e illeggibile per rispondere a questa domanda.
psytek,

1
sarebbe bello se questo almeno funzionasse. prova questo numero "17371830" diventa "173.718.3.0" =)
holms

5
Periodi? Non è nemmeno possibile, holms. Questo pezzo di spazzatura ignora totalmente le impostazioni locali. Mi chiedo come hai ottenuto quel risultato. Il tuo esempio produce '17, 371.830 'per me, come previsto.
Kasey Kirkham,

11
Per rendere questa una funzione, suggerirei: 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 per mantenere il tema dell'offuscamento.
quantico

95

Ecco il codice di raggruppamento delle impostazioni internazionali dopo aver rimosso parti non pertinenti e averlo pulito un po ':

(Quanto segue funziona solo per numeri interi)

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'

Ci sono già alcune buone risposte qui. Voglio solo aggiungere questo per riferimento futuro. In Python 2.7 ci sarà un identificatore di formato per migliaia di separatori. Secondo i documenti di Python funziona così

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

In python3.1 puoi fare la stessa cosa in questo modo:

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

Sì, i modi più difficili sono principalmente per le persone sui vecchi Python, come quelli spediti con RHEL e altre distro di supporto a lungo termine.
Mike DeSimone,

3
come esprimerlo con stringhe di formato? "%, d"% 1234567 non funziona
Frederic Bazin

93

Sono sorpreso che nessuno abbia menzionato che puoi farlo con f-string in Python 3.6 così semplice:

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

... dove la parte dopo i due punti è l'identificatore del formato. La virgola è il carattere separatore che desideri, quindi f"{num:_}"utilizza caratteri di sottolineatura anziché una virgola.

Ciò equivale all'utilizzo format(num, ",")per le versioni precedenti di Python 3.


Questo è più facile di qualsiasi delle risposte più votate e non richiede ulteriori importazioni.
Livello Z4

39

Ecco una sostituzione regex di una riga:

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

Funziona solo per uscite inegral:

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 per i float con meno di 4 cifre, modificare l'identificatore di formato in %.3f:

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

NB: non funziona correttamente con più di tre cifre decimali in quanto tenterà di raggruppare la parte decimale:

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

Come funziona

Analizziamolo:

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
usa la modalità dettagliata e puoi avere commenti direttamente all'interno del codice
Daniel Stracaboško

Non potresti sostituire "(?! \ D)" con "$"?
GL2014

28

Questo è quello che faccio per i galleggianti. Anche se, onestamente, non sono sicuro per quali versioni funziona - sto usando 2.7:

my_number = 4385893.382939491

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

Ritorni: 4.385.893,38

Aggiornamento: di recente ho avuto un problema con questo formato (non saprei dirti il ​​motivo esatto), ma sono stato in grado di risolverlo lasciando cadere 0:

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

19

Puoi anche usare '{:n}'.format( value ) per una rappresentazione locale. Penso che questo sia il modo più semplice per una soluzione locale.

Per ulteriori informazioni, cercare thousandsin Python DOC .

Per la valuta, è possibile utilizzare locale.currency, impostando la bandiera grouping:

Codice

import locale

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

Produzione

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

14

Espandendo leggermente la risposta di Ian Schneider:

Se si desidera utilizzare un separatore di migliaia personalizzato, la soluzione più semplice è:

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

Esempi

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

Se vuoi la rappresentazione tedesca in questo modo, diventa un po 'più complicata:

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

Leggermente più corto:'{:_.2f}'.format(12345.6789).replace('.', ',').replace('_', '.')
Tom Pohl,

12

Sono sicuro che ci deve essere una funzione di libreria standard per questo, ma è stato divertente provare a scriverlo da solo usando la ricorsione, quindi ecco cosa mi è venuto in mente:

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)

Detto questo, se qualcun altro trova un modo standard per farlo, dovresti usarlo invece.


Sfortunatamente non funziona in tutti i casi. intToStringWithCommas (1000.1) -> '1.0001.000'
Nadia Alramli,

Ha detto specificamente numeri interi e che dovrebbe essere il più semplice possibile, quindi ho deciso di non gestire tipi di dati diversi dai numeri interi. L'ho anche reso esplicito nel nome della funzione _int_ToStringWithCommas. Ora ho anche aggiunto un aumento per renderlo più chiaro.
Mark Byers,

8

Dai commenti alla ricetta 498181 di Activestate ho rielaborato questo:

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

Utilizza la funzione delle espressioni regolari: lookahead, cioè (?=\d)per assicurarsi che solo i gruppi di tre cifre che hanno una cifra "dopo" ottengano una virgola. Dico 'after' perché la stringa è inversa a questo punto.

[::-1] inverte semplicemente una stringa.



7

Python 3

-

Numeri interi (senza decimali):

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

-

Galleggianti (con decimale):

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

dove il numero prima f specifica il numero di posizioni decimali.

-

indennità

Funzione di avvio rapido e sporco per il sistema di numerazione di lakh / crore indiani (12,34.567):

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


5

dalla versione 2.6 di Python puoi farlo:

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

Per le versioni Python <2.6 e solo per vostra informazione, ecco 2 soluzioni manuali, che trasformano i float in in ma i numeri negativi funzionano correttamente:

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)

alcune cose da notare qui:

  • questa riga: string = '% d'% number converte magnificamente un numero in una stringa, supporta i negativi e fa cadere le frazioni dai float, rendendoli ints;
  • gli indici di questa sezione [:: - 3] restituiscono ogni terzo elemento a partire dalla fine, quindi ho usato un'altra fetta [1:] per rimuovere l'ultimo elemento perché non ho bisogno di una virgola dopo l'ultimo numero;
  • questo condizionale se l [indice]! = '-' viene utilizzato per supportare numeri negativi, non inserire una virgola dopo il segno meno.

E una versione più 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

Sono un principiante di Python, ma un programmatore esperto. Ho Python 3.5, quindi posso semplicemente usare la virgola, ma questo è comunque un esercizio di programmazione interessante. Considera il caso di un numero intero senza segno. Il programma Python più leggibile per l'aggiunta di migliaia di separatori sembra essere:

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)

È anche possibile utilizzare una comprensione dell'elenco:

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)

Questo è più corto e potrebbe essere una fodera, ma dovrai fare un po 'di ginnastica mentale per capire perché funziona. In entrambi i casi otteniamo:

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 prima versione è la scelta più sensata, se si desidera comprendere il programma.


1

Eccone uno che funziona anche con i float:

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

Esempio di utilizzo:

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

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

1

Un liner per Python 2.5+ e Python 3 (solo int positivo):

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

1

Soluzione universale

Ho riscontrato alcuni problemi con il separatore punti nelle precedenti risposte con il voto più alto. Ho progettato una soluzione universale in cui è possibile utilizzare ciò che si desidera come un separatore mille senza modificare le impostazioni internazionali . So che non è la soluzione più elegante, ma fa il lavoro. Sentiti libero di migliorarlo!

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

Questo fa soldi insieme alle virgole

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

Ho una versione Python 2 e Python 3 di questo codice. So che la domanda è stata posta per Python 2 ma ora (8 anni dopo lol) le persone probabilmente useranno Python 3.

Codice 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))        


Codice Python 2: (Modifica. Il codice Python 2 non funziona. Sto pensando che la sintassi sia diversa).

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

Sto usando Python 2.5, quindi non ho accesso alla formattazione integrata.

Ho esaminato l'intcomma del codice Django (intcomma_recurs nel codice seguente) e ho capito che è inefficiente, perché è ricorsivo e anche compilare la regex ad ogni corsa non è una buona cosa. Questo non è necessario un "problema" in quanto il django non è realmente così concentrato su questo tipo di performance di basso livello. Inoltre, mi aspettavo un fattore 10 di differenza nelle prestazioni, ma è solo 3 volte più lento.

Per curiosità ho implementato alcune versioni di intcomma per vedere quali sono i vantaggi prestazionali quando si utilizza regex. I miei dati di test concludono un leggero vantaggio per questo compito, ma sorprendentemente non molto.

Sono stato anche contento di vedere quello che sospettavo: l'uso del metodo reverse xrange non è necessario nel caso no-regex, ma rende il codice leggermente migliore al costo di prestazioni del 10% circa.

Inoltre, suppongo che ciò che stai passando sia una stringa e assomigli in qualche modo a un numero. Risultati indeterminati altrimenti.

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

Ed ecco i risultati del test:

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

Ho pensato che la soluzione one-regex di Daniel Fortunov sarebbe stata la numero 1 e avrebbe battuto tutti gli algoritmi perché regex è così raffinato / ottimizzato e codificato in C, ma no .. Immagino che lo schema e il lookahead siano troppo costosi. cade a circa il doppio del tempo dell'intcomma sopra, anche con la precompilazione della regex.
parità 3


-1

Ecco un'altra variante che utilizza una funzione di generatore che funziona per numeri interi:

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)]))

Ed ecco un test:

>>> 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 sottoclasse long(o float, o altro). Questo è molto pratico, perché in questo modo puoi ancora usare i tuoi numeri in operazioni matematiche (e quindi il codice esistente), ma verranno tutti stampati bene nel tuo terminale.

>>> 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
Mi piace l'idea della sottoclasse, ma è __repr__()il metodo corretto da sostituire? Suggerirei di scavalcare __str__()e lasciare __repr__()da solo, perché int(repr(number(928374)))dovrebbe funzionare, ma int()soffocare le virgole.
Steveha,

@steveha ha un buon punto, ma la giustificazione avrebbe dovuto essere che number(repr(number(928374)))non funziona, non int(repr(number(928374))). Tuttavia, per far funzionare direttamente questo approccio con print, come richiesto dall'OP, il __str__()metodo dovrebbe essere quello sostituito anziché __repr__(). Indipendentemente da ciò, sembra esserci un bug nella logica di inserimento della virgola principale.
martineau,

-1

Italia:

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

-8

Per i galleggianti:

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

Per ints:

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

5
Ciò rimuove le virgole. Per quanto utile, l'OP ha chiesto un modo per aggiungerli . Inoltre, qualcosa del genere float('1,234.52'.translate(None, ','))potrebbe essere più semplice e forse più veloce.
In pausa fino a nuovo avviso.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.