Sayıları virgüllerle binlerce ayırıcı olarak nasıl yazdırabilirim?


754

Binlerce ayırıcı olarak virgülle Python 2.6.1'de bir tam sayı yazdırmaya çalışıyorum . Örneğin, ben sayısını göstermek istiyorum 1234567olarak 1,234,567. Bunu nasıl yapabilirim? Google'da birçok örnek gördüm, ancak en basit pratik yolu arıyorum.

Noktalar ve virgül arasında karar vermek için bölgeye özgü olması gerekmez. Mümkün olduğunca basit bir şeyi tercih ederim.

Yanıtlar:


1739

Yerel ayar farkında değil

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

Yerel ayar farkında

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

Referans

Biçim Özelliğine Göre Mini Dil ,

','Seçenek binlerce ayırıcı için bir virgül kullanımını bildirir. Yerel ayarlara uygun ayırıcı için 'n'bunun yerine tamsayı sunum türünü kullanın.


24
Bunun ABD dışında ve diğer birkaç yer için doğru olmayacağını unutmayın, bu durumda seçilen locale.format () doğru cevaptır.
Gringo Suave

11
Anahtar kelime bağımsız değişken formu:{val:,}.format(val=val)
CivFan

11
Çok teşekkürler.
Parasal

3
(.) noktasını sadece ayırıcı olarak kullandığımız Portekiz için: {:,} ". format (değer) .replace (',', '.')

13
Python 3.6 ve sonraki sürümlerde, f-dizeleri daha fazla kolaylık sağlar. Ör.f"{2 ** 64 - 1:,}"
CJ Gaconnet

285

Bunu çalışmak için aldım:

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

Elbette, uluslararasılaştırma desteğine ihtiyacınız yok , ancak açık, özlü ve yerleşik bir kütüphane kullanıyor.

PS "% d" her zamanki% tarzı biçimlendiricidir. Yalnızca bir formatlayıcıya sahip olabilirsiniz, ancak alan genişliği ve hassasiyet ayarları için ihtiyacınız olan her şey olabilir.

PPS localeİşe alamıyorsanız , Mark'ın cevabının değiştirilmiş bir versiyonunu öneririm:

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)

Özyineleme negatif durum için yararlıdır, ancak virgül başına bir özyineleme benim için biraz fazla görünüyor.


14
Kodunuzu denedim ve maalesef şunu alıyorum: "locale.Error: desteklenmeyen yerel ayar". : -s
Mark Byers

11
Mark: Linux kullanıyorsanız, /etc/locale.gen dosyasında veya glibc'nizin yerel ayarlarını oluşturmak için ne kullandığına bakmak isteyebilirsiniz. Ayrıca "" en "," en_US.utf8 "," en_US.UTF-8 ", 'en_UK" (sp?) Vb. Denemek isteyebilirsiniz. Mikez: Bir kitap olmalı: "Dr. PEP: Veya Endişelenmeyi ve Sevmeyi Durdurmayı Nasıl Öğrenirim docs.python.org. " Python 1.5.6 çevresindeki tüm kütüphaneleri ezberlemekten vazgeçtim. Gelince locale, olabildiğince az kullanıyorum.
Mike DeSimone

10
setlocaleUmarım uygun olan varsayılanı kullanmak için '' düğmesini kullanabilirsiniz.
Mark Ransom

24
Bunu deneyin: locale.setlocale (locale.LC_ALL, '') Benim için çalıştı
Nadia Alramli

1
Akıllı olmasına rağmen, global ayarları yapan işlevleri sevmiyorum ... 'blah'.format () kullanmak daha iyi bir yol.
Cerin

132

Verimsizlik ve okunamazlık için yenilmesi zor:

>>> 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
Bu soruyu cevaplamak için en verimsiz ve okunamayan yöntem için seçildi.
Ocak'ta psytek

1
en azından işe yararsa iyi olurdu. bu numarayı deneyin "17371830" "173.718.3.0" =) olur
holms

5
Süreleri? Bu bile mümkün değil, holms. Bu önemsiz parça yerel ayarları tamamen yok sayar. Bu sonucu nasıl aldığını merak ediyorum. Örneğiniz beklendiği gibi benim için '17, 371,830 'üretir.
Kasey Kirkham

11
Bunu bir işlev haline getirmek için önerebilirim: 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))sadece gizleme temasını korumak için.
kuantum

95

Alakasız parçaları çıkardıktan ve biraz temizledikten sonra yerel ayar gruplama kodu:

(Aşağıdaki yalnızca tamsayılar için geçerlidir)

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'

Burada zaten bazı iyi cevaplar var. Bunu ileride başvurmak üzere eklemek istiyorum. Python 2.7'de binlerce ayırıcı için bir format belirleyici olacaktır. Python belgelerine göre böyle çalışır

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

Python3.1'de aynı şeyi şu şekilde yapabilirsiniz:

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

Evet, daha zor yollar, RHEL ve diğer uzun vadeli destek dağıtımlarıyla birlikte gönderilenler gibi daha eski Python'lardaki insanlar içindir.
Mike DeSimone

3
bunu biçim dizeleriyle nasıl ifade edebilirim? "%, d"% 1234567 çalışmıyor
Frederic Bazin

92

Kimsenin bunu Python 3.6'daki f-dizeleri ile bu kadar kolay yapabileceğinizi söylemediğine şaşırdım:

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

... iki nokta üst üste işaretinden sonraki kısım biçim belirleyicidir. Virgül istediğiniz ayırıcı karakterdir, bu nedenle f"{num:_}"virgül yerine alt çizgi kullanır.

Bu, format(num, ",")python 3'ün eski sürümleri için kullanılmaya eşdeğerdir .


39

İşte tek satırlık normal ifade:

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

Sadece inegral çıkışları için çalışır:

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'

Veya 4 basamaktan daha küçük şamandıralar için biçim belirleyiciyi şu şekilde değiştirin %.3f:

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

Not: Ondalık bölümü gruplamaya çalışacağı için üçten fazla ondalık basamakla düzgün çalışmıyor:

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

Nasıl çalışır

Hadi yıkalım:

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
ayrıntılı modu kullanın ve kodun içinde yorum yapabilirsiniz
Daniel Stracaboško

"(?! \ D)" yerine "$" yazamaz mısınız?
GL2014

28

Şamandıralar için yaptığım bu. Dürüst olmak gerekirse, hangi sürümler için çalıştığından emin değilim - 2.7 kullanıyorum:

my_number = 4385893.382939491

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

İadeler: 4.385.893,38

Güncelleme: Son zamanlarda bu formatla ilgili bir sorunum vardı (tam nedenini söyleyemedim), ancak bırakarak düzelttim 0:

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

19

'{:n}'.format( value )Yerel bir gösterim için de kullanabilirsiniz . Bence bu bir yerel çözüm için en basit yol.

Daha fazla bilgi için aramak thousandsiçinde Python DOC .

Para birimi için, locale.currencybayrağı ayarlayarak şunları kullanabilirsiniz grouping:

kod

import locale

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

Çıktı

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

13

Ian Schneider'ın cevabını biraz genişletmek:

Özel bir binlerce ayırıcı kullanmak istiyorsanız, en basit çözüm:

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

Örnekler

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

Alman temsilinin böyle olmasını istiyorsanız, biraz daha karmaşık hale gelir:

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

Biraz daha kısa:'{:_.2f}'.format(12345.6789).replace('.', ',').replace('_', '.')
Tom Pohl

12

Bunun için standart bir kütüphane işlevi olması gerektiğinden eminim, ancak özyineleme kullanarak kendim yazmaya çalışmak eğlenceliydi, bu yüzden burada ne buldum:

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)

Söyledikten sonra, başka biri bunu yapmak için standart bir yol bulursa, bunun yerine bunu kullanmalısınız.


Maalesef her durumda çalışmaz. intToStringWithCommas (1000.1) -> '1.0001.000'
Nadia Alramli

Özellikle tamsayıları söyledi ve olabildiğince basit olması gerektiğini söyledi, bu yüzden tamsayıların dışındaki veri tiplerini işlememeye karar verdim. Ayrıca işlev adı _int_ToStringWithCommas açıkça yaptı. Şimdi daha açık hale getirmek için bir yükseltme ekledim.
Mark Byers

8

Gönderen yorumlarla ActiveState reçeteye 498181 Ben bu yeniden işlenmiş:

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

Normal ifadeler özelliğini kullanır: lookahead ie (?=\d), yalnızca "sonra" basamağı olan üç basamaklı grupların virgül aldığından emin olmak için. Ben 'sonra' diyorum çünkü dize bu noktada tersidir.

[::-1] sadece bir dizeyi tersine çevirir.



7

Python 3

-

Tamsayılar (ondalık olmadan):

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

-

Şamandıralar (ondalık ile):

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

burada önceki sayı fondalık basamak sayısını belirtir.

-

Bonus

Hint lakhs / crores numaralandırma sistemi için hızlı ve kirli başlangıç ​​fonksiyonu (12,34,567):

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


5

Python sürüm 2.6'dan şunları yapabilirsiniz:

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

Python sürümleri <2.6 ve sadece bilginiz için, burada 2 manuel çözüm var, bunlar şamandıraları intsa çeviriyor, ancak negatif sayılar doğru çalışıyor:

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)

burada dikkat edilmesi gereken birkaç nokta:

  • bu satır: string = '% d'% sayı , bir sayıyı dizeye güzel bir şekilde dönüştürür, negatifleri destekler ve kayan noktalardan kesirler bırakır ve onları ints yapar;
  • bu dilim dizinleri [:: - 3] her üçüncü öğeyi sondan başlayarak döndürür, bu yüzden son öğeyi kaldırmak için başka bir dilim [1:] kullandım çünkü son sayıdan sonra virgül kullanmam;
  • bu şartlı ! '-' l [index] = eğer negatif sayıları desteklemek için kullanılıyor, eksi işaretinden sonra virgül ekleme yok.

Ve daha sert bir versiyon:

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

Ben bir Python acemiyim, ama deneyimli bir programcıyım. Python 3.5 var, bu yüzden sadece virgül kullanabilirsiniz, ama yine de ilginç bir programlama alıştırması. İmzasız bir tamsayı düşünün. Binlerce ayırıcı eklemek için en okunabilir Python programı şöyledir:

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)

Bir liste kavrayışı kullanmak da mümkündür:

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)

Bu daha kısa ve tek bir astar olabilir, ancak neden çalıştığını anlamak için bazı zihinsel jimnastik yapmalısınız. Her iki durumda da:

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

Programın anlaşılmasını istiyorsanız ilk sürüm daha mantıklı bir seçimdir.


1

İşte şamandıralar için de çalışan:

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

Kullanım Örneği:

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

1
float2comma(12031023.1323)dönüş: '12, 031,023.132,3 '
demux

1

Python 2.5+ ve Python 3 için bir astar (yalnızca pozitif int):

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

1

Evrensel çözüm

Önceki en iyi oylanan cevaplarda nokta ayırıcıyla ilgili bazı sorunlar buldum. Yerel ayarı değiştirmeden binlik ayırıcı olarak istediğiniz her şeyi kullanabileceğiniz evrensel bir çözüm tasarladım . En zarif çözüm olmadığını biliyorum, ama işi hallediyor. Geliştirmek için çekinmeyin!

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

Bu virgülle birlikte para yapar

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

Bu kodun bir python 2 ve python 3 sürümü var. Sorunun python 2 için sorulduğunu biliyorum ama şimdi (8 yıl sonra lol) insanlar muhtemelen python 3 kullanacak.

Python 3 Kodu:

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


Python 2 Kodu: (Düzenle. Python 2 kodu çalışmıyor. Sözdiziminin farklı olduğunu düşünüyorum).

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

Yerleşik biçimlendirmeye erişimim olmadığından python 2.5 kullanıyorum.

Ben Django kodu intcomma (aşağıdaki kod intcomma_recurs) baktı ve bunun özyineli olduğunu fark ettim, çünkü özyinelemeli ve aynı zamanda her çalışmada regex derleme de iyi bir şey değil. Django gerçekten bu tür düşük seviyeli performansa odaklanmış OLMADIĞI için bu bir 'sorun' gerekmez. Ayrıca, performansta 10 fark faktörü bekliyordum, ancak sadece 3 kat daha yavaş.

Meraktan, regex kullanırken performans avantajlarının ne olduğunu görmek için birkaç intcomma sürümü uyguladım. Test verilerim bu görev için hafif bir avantaj sağlıyor, ancak şaşırtıcı bir şekilde hiç de değil.

Ben de şüphelendiğimi görmek için memnun oldu: noge-regex durumda ters xrange yaklaşımını kullanmak gereksizdir, ancak kod ~% 10 performans pahasına biraz daha iyi görünmesini sağlar.

Ayrıca, geçtiğiniz şeyin bir dize olduğunu ve bir sayıya benzediğini varsayıyorum. Sonuçlar başka türlü belirlenmedi.

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

İşte test sonuçları:

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

Daniel Fortunov'un tek regex çözümünün # 1 olacağını ve regex'in çok rafine edilmiş / optimize edilmiş ve C'de kodlanmış olduğu için hayır olduğunu düşündüm, ama hayır .. Sanırım desen ve ileri bakış çok pahalı. regex'i önceden derlerken bile, yukarıdaki intcomma'nın yaklaşık iki katı zamanda düşer.
parity3


-1

Tamsayılar için çalışan bir jeneratör işlevi kullanan başka bir varyant:

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

Ve işte bir 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

Sadece alt sınıf long(veya float, ya da her neyse). Bu son derece pratiktir, çünkü bu şekilde sayılarınızı hala matematik işlemlerinde (ve dolayısıyla mevcut kodda) kullanabilirsiniz, ancak hepsi terminalinizde güzel bir şekilde yazdırılacaktır.

>>> 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
Alt sınıf fikrini seviyorum, ancak __repr__()geçersiz kılmak için doğru yöntem mi? Geçersiz kılmayı __str__()ve __repr__()yalnız bırakmayı öneriyorum , çünkü int(repr(number(928374)))çalışması gerekiyor, ancak int()virgüllere boğuluyor.
steveha

@steveha'nın iyi bir noktası var, ancak gerekçe number(repr(number(928374)))işe yaramıyor olmalı , değil int(repr(number(928374))). Yine de, bu yaklaşımın doğrudan printOP ile çalışmasını sağlamak için , __str__()yöntem yerine geçersiz kılınan yöntem olmalıdır __repr__(). Ne olursa olsun, çekirdek virgül ekleme mantığında bir hata var gibi görünüyor.
martineau

-1

İtalya:

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

-8

Şamandıralar için:

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

Ints için:

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

5
Bu virgülleri kaldırır . Kullanışlı olsa da, OP bunları eklemek için bir yol istedi . Ayrıca, böyle bir şey float('1,234.52'.translate(None, ','))daha basit ve muhtemelen daha hızlı olabilir.
sonraki duyuruya kadar duraklatıldı.
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.