Jak wydrukować liczbę przecinkami jako separatory tysięcy?


752

Próbuję wydrukować liczbę całkowitą w Pythonie 2.6.1 z przecinkami jako tysiące separatorów. Na przykład chcę pokazać numer 1234567jako 1,234,567. Jak miałbym to zrobić? Widziałem wiele przykładów w Google, ale szukam najprostszego praktycznego sposobu.

Aby wybierać między kropkami a przecinkami, nie musi być zależny od ustawień regionalnych. Wolałbym coś tak prostego, jak to możliwe.

Odpowiedzi:


1737

Ustawienia regionalne są nieświadome

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

Świadome ustawienia regionalne

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

Odniesienie

Per specyfikacji formatu Mini-język ,

Ta ','opcja sygnalizuje użycie przecinka dla separatora tysięcy. W przypadku separatora rozpoznającego ustawienia narodowe użyj 'n'zamiast tego typu prezentacji liczby całkowitej.


24
Zauważ, że nie będzie to poprawne poza USA i kilkoma innymi miejscami, w takim przypadku wybrana locale.format () jest poprawną odpowiedzią.
Gringo Suave,

10
Forma argumentu słowa kluczowego:{val:,}.format(val=val)
CivFan,

11
Wielkie dzięki. W przypadku kwot pieniężnych z 2 miejscami po przecinku - „{:,. 2f}”. Format (wartość)
dlink

3
dla Portugalii, gdzie używamy punktu (.) jako separatora, po prostu: {:,} ". format (wartość) .replace (',', '.')

13
W Pythonie 3.6 i nowszych ciągi F zapewniają jeszcze większą wygodę. Np.f"{2 ** 64 - 1:,}"
CJ Gaconnet,

285

Mam to do pracy:

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

Jasne, nie potrzebujesz wsparcia na rzecz internacjonalizacji, ale jest przejrzysty, zwięzły i korzysta z wbudowanej biblioteki.

PS Ten „% d” jest zwykłym formatyzatorem w stylu%. Możesz mieć tylko jeden formatyzator, ale może to być wszystko, czego potrzebujesz pod względem ustawień szerokości i precyzji pola.

PPS Jeśli nie możesz dostać locale do pracy, proponuję zmodyfikowaną wersję odpowiedzi Marka:

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)

Rekurencja jest przydatna w przypadku negatywnym, ale jedna rekurencja na przecinek wydaje mi się nieco nadmierna.


14
Próbowałem twojego kodu i niestety dostaję: „locale.Error: unupported locale setting”. : -s
Mark Byers

11
Mark: Jeśli korzystasz z Linuksa, możesz chcieć spojrzeć na to, co znajduje się w /etc/locale.gen, lub cokolwiek, czego używa twój glibc do budowania swoich ustawień narodowych. Możesz także spróbować użyć „” en ”,„ en_US.utf8 ”,„ en_US.UTF-8 ”,„ en_UK ”(sp?) Itp. Mikez: Potrzebna jest książka:„ Dr. PEP: Or Jak nauczyłem się przestać martwić i pokochać docs.python.org. ” Zrezygnowałem z zapamiętywania wszystkich bibliotek w Pythonie 1.5.6. Jeśli chodzi o to locale, używam tak mało, jak mogę.
Mike DeSimone

10
Możesz użyć „”, setlocaleaby użyć domyślnej, która, mam nadzieję, będzie odpowiednia.
Mark Ransom

24
Spróbuj tego: locale.setlocale (locale.LC_ALL, '') To zadziałało dla mnie
Nadia Alramli

1
Chociaż sprytne, nie lubię funkcji, które zmieniają ustawienia globalne ... Lepszym sposobem jest użycie „blah'.format ().
Cerin,

132

Trudno jest pokonać nieefektywność i nieczytelność:

>>> 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
Zagłosowano za najbardziej nieefektywną i nieczytelną metodą odpowiedzi na to pytanie.
psytek

1
byłoby miło, gdyby to przynajmniej działało. spróbuj tego numeru „17371830” staje się „173.718.3.0” =)
holms

5
Okresy? To nie jest nawet możliwe, holms. Ten kawałek śmieci całkowicie ignoruje ustawienia regionalne. Zastanawiam się, skąd masz ten wynik. Twój przykład produkuje dla mnie „17, 371 830”, zgodnie z oczekiwaniami.
Kasey Kirkham,

11
Aby uczynić to funkcją, sugerowałbym: 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))po prostu zachować motyw zaciemniający.
kwantowy

95

Oto kod grupujący ustawienia regionalne po usunięciu nieistotnych części i drobnym ich oczyszczeniu:

(Poniższe działa tylko dla liczb całkowitych)

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'

Tutaj jest już kilka dobrych odpowiedzi. Chcę tylko dodać to na przyszłość. W Pythonie 2.7 pojawi się specyfikator formatu dla separatora tysięcy. Według dokumentów Pythona działa to tak

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

W python3.1 możesz zrobić to samo:

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

Tak, trudniejsze sposoby są głównie dla starszych użytkowników Pythona, takich jak te dostarczane z RHEL i innymi długoterminowymi dystrybucjami wsparcia.
Mike DeSimone

3
jak wyrazić to za pomocą ciągów formatu? „%, d”% 1234567 nie działa
Frederic Bazin

91

Dziwi mnie, że nikt nie wspomniał, że można to zrobić za pomocą f-stringów w Pythonie 3.6 tak łatwo:

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

... gdzie część po dwukropku jest specyfikatorem formatu. Przecinek to pożądany znak separatoraf"{num:_}" zamiast podkreślenia używa podkreślników.

Jest to równoważne z używaniem format(num, ",")dla starszych wersji Pythona 3.


39

Oto zamiennik wyrażenia regularnego w jednym wierszu:

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

Działa tylko w przypadku danych wyjściowych:

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'

Lub w przypadku liczb zmiennoprzecinkowych zawierających mniej niż 4 cyfry zmień specyfikator formatu na %.3f:

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

Uwaga: Nie działa poprawnie z więcej niż trzema cyframi dziesiętnymi, ponieważ będzie próbował zgrupować część dziesiętną:

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

Jak to działa

Rozbijmy to:

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
użyj trybu
pełnego,

Czy nie możesz zamienić „(?! \ D)” na „$”?
GL2014

28

To właśnie robię dla pływaków. Chociaż, szczerze mówiąc, nie jestem pewien, dla których wersji to działa - używam 2.7:

my_number = 4385893.382939491

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

Zwraca: 4 385 893,38

Aktualizacja: Niedawno miałem problem z tym formatem (nie mogłem podać dokładnego powodu), ale mogłem go naprawić, upuszczając 0:

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

19

Możesz także użyć '{:n}'.format( value )do reprezentacji ustawień regionalnych. Myślę, że to najprostszy sposób na rozwiązanie regionalne.

Aby uzyskać więcej informacji, wyszukaj thousandsw Python DOC .

W przypadku waluty możesz użyć locale.currency, ustawiając flagę grouping:

Kod

import locale

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

Wynik

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

13

Nieznacznie rozszerzając odpowiedź Iana Schneidera:

Jeśli chcesz użyć niestandardowego separatora tysięcy, najprostszym rozwiązaniem jest:

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

Przykłady

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

Jeśli chcesz taką reprezentację Niemiec, staje się ona nieco bardziej skomplikowana:

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

Nieco krótszy:'{:_.2f}'.format(12345.6789).replace('.', ',').replace('_', '.')
Tom Pohl

12

Jestem pewien, że musi istnieć standardowa funkcja biblioteki, ale fajnie było spróbować napisać ją samemu za pomocą rekurencji, więc oto, co wymyśliłem:

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)

Powiedziawszy to, jeśli ktoś inny znajdzie standardowy sposób na zrobienie tego, powinieneś go użyć.


Niestety nie działa we wszystkich przypadkach. intToStringWithCommas (1000.1) -> „1.0001,000”
Nadia Alramli

W szczególności powiedział liczby całkowite i że powinno to być tak proste, jak to możliwe, więc postanowiłem nie obsługiwać typów danych innych niż liczby całkowite. Podałem to również wyraźnie w nazwie funkcji _int_ToStringWithCommas. Teraz dodałem także podwyżkę, aby była bardziej przejrzysta.
Mark Byers,

8

Od komentarzy do przepisu activestate 498181 Przerobiłem to:

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

Wykorzystuje funkcję wyrażeń regularnych: lookahead, tj. (?=\d)Aby upewnić się, że tylko grupy trzech cyfr, które mają cyfrę „po”, otrzymają przecinek. Mówię „po”, ponieważ w tym momencie ciąg znaków jest odwrotny.

[::-1] po prostu odwraca ciąg.



7

Python 3

-

Liczby całkowite (bez miejsc dziesiętnych):

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

-

Liczba zmiennoprzecinkowa (z przecinkiem):

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

gdzie liczba poprzednia fokreśla liczbę miejsc dziesiętnych.

-

Premia

Szybka i brudna funkcja startowa dla indyjskiego systemu numeracji lakhs / crores (12 34567):

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


5

od wersji Python 2.6 możesz to zrobić:

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

Dla wersji Pythona <2.6 i tylko dla twojej informacji, oto 2 ręczne rozwiązania, zmieniają liczby zmiennoprzecinkowe na liczby całkowite, ale liczby ujemne działają poprawnie:

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)

kilka rzeczy do zauważenia tutaj:

  • ta linia: string = '% d'% number pięknie konwertuje liczbę na ciąg, obsługuje negatywy i upuszcza ułamki zwykłe, czyniąc je intami;
  • ten wycinek indeksuje [:: - 3] zwraca co trzeci element, zaczynając od końca, więc użyłem innego wycinka [1:], aby usunąć ostatni element, ponieważ nie potrzebuję przecinka po ostatnim numerze;
  • jest to warunek, jeśli l [indeks]! = '-' jest używany do obsługi liczb ujemnych, nie wstawiaj przecinka po znaku minus.

I bardziej hardkorowa wersja:

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

Jestem początkującym w Pythonie, ale doświadczonym programistą. Mam Python 3.5, więc mogę po prostu użyć przecinka, ale jest to jednak interesujące ćwiczenie programistyczne. Rozważ przypadek liczby całkowitej bez znaku. Najbardziej czytelnym programem do dodawania tysięcy separatorów w języku Python jest:

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)

Możliwe jest również użycie listowego zrozumienia:

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)

To jest krótsze i może być jedno-liniowe, ale będziesz musiał zrobić gimnastykę umysłową, aby zrozumieć, dlaczego to działa. W obu przypadkach otrzymujemy:

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

Pierwsza wersja jest bardziej rozsądnym wyborem, jeśli chcesz, aby program był zrozumiały.


1

Oto jeden, który działa również dla pływaków:

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

Przykład użycia:

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

1
float2comma(12031023.1323)zwraca: '12, 031,023.132,3 '
demultipleksacja

1

Jedna linijka dla Python 2.5+ i Python 3 (tylko dodatnie int):

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

1

Uniwersalne rozwiązanie

Znalazłem pewne problemy z separatorem kropek w poprzednich najczęściej głosowanych odpowiedziach. Zaprojektowałem uniwersalne rozwiązanie, w którym możesz użyć, co chcesz, jako separatora tysięcy bez modyfikowania ustawień regionalnych . Wiem, że to nie jest najbardziej eleganckie rozwiązanie, ale wykonuje zadanie. Możesz to poprawić!

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

To robi pieniądze wraz z przecinkami

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

Mam wersję tego kodu w języku Python 2 i Python 3. Wiem, że pytanie zostało zadane dla Pythona 2, ale teraz (8 lat później) ludzie prawdopodobnie będą używać Pythona 3.

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


Kod Python 2: (Edytuj. Kod Python 2 nie działa. Myślę, że składnia jest inna).

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

Używam Pythona 2.5, więc nie mam dostępu do wbudowanego formatowania.

Spojrzałem na kod Django intcomma (intcomma_recurs w kodzie poniżej) i zdałem sobie sprawę, że jest nieefektywny, ponieważ jest rekurencyjny, a także kompilacja wyrażenia regularnego przy każdym uruchomieniu również nie jest dobrą rzeczą. Nie jest to konieczny „problem”, ponieważ django tak naprawdę nie koncentruje się na tego rodzaju wydajności na niskim poziomie. Spodziewałem się też 10-krotnej różnicy w wydajności, ale jest ona tylko 3-krotnie wolniejsza.

Z ciekawości zaimplementowałem kilka wersji intcomma, aby zobaczyć, jakie są zalety wydajności podczas używania wyrażenia regularnego. Moje dane testowe wskazują na niewielką zaletę tego zadania, ale zaskakująco niewiele.

Z przyjemnością zobaczyłem również to, co podejrzewałem: stosowanie odwrotnego zakresu xrange jest niepotrzebne w przypadku braku wyrażenia regularnego, ale sprawia, że ​​kod wygląda nieco lepiej kosztem ~ 10% wydajności.

Zakładam też, że to, co przekazujesz, to ciąg znaków i wygląda trochę jak liczba. Wyniki nie zostały określone inaczej.

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

A oto wyniki testu:

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

Myślałem, że jedno-regexowe rozwiązanie Daniela Fortunova będzie nr 1 i pobije wszystkie algorytmy, ponieważ regex jest tak dopracowany / zoptymalizowany i zakodowany w C, ale nie ... Myślę, że wzorzec i oczekiwania są zbyt drogie. wpada około dwa razy szybciej niż intcomma powyżej, nawet przy prekompilacji wyrażenia regularnego.
parzystość3


-1

Oto inny wariant wykorzystujący funkcję generatora, która działa dla liczb całkowitych:

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

A oto 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

Po prostu podklasa long( floatlub cokolwiek innego). Jest to bardzo praktyczne, ponieważ w ten sposób nadal możesz używać swoich liczb w operacjach matematycznych (a zatem i istniejącym kodzie), ale wszystkie będą ładnie drukować w twoim terminalu.

>>> 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
Podoba mi się pomysł na podklasę, ale czy jest __repr__()poprawna metoda zastąpienia? Sugerowałbym zastąpienie __str__()i pozostawienie w __repr__()spokoju, ponieważ int(repr(number(928374)))powinien działać, ale int()będzie się dusił przecinkami.
steveha,

@steveha ma rację, ale uzasadnienie powinno być takie, że number(repr(number(928374)))nie działa, nie int(repr(number(928374))). Niemniej jednak, aby to podejście działało bezpośrednio print, zgodnie z żądaniem PO, __str__()metoda powinna być zastąpiona __repr__(). Niezależnie od tego wydaje się, że w logice wstawiania przecinka występuje błąd.
martineau

-1

Włochy:

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

-8

Dla pływaków:

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

Dla ints:

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

5
To usuwa przecinki. Choć przydatny, PO poprosił o sposób ich dodania . Poza tym coś takiego float('1,234.52'.translate(None, ','))może być prostsze i być może szybsze.
Wstrzymano do odwołania.
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.