วิธีพิมพ์หมายเลขด้วยเครื่องหมายจุลภาคเป็นตัวคั่นหลักพัน


754

ฉันพยายามพิมพ์จำนวนเต็มในPython 2.6.1ด้วยเครื่องหมายจุลภาคเป็นตัวคั่นหลักพัน ตัวอย่างเช่นผมต้องการที่จะแสดงตัวเลขเป็น1234567 1,234,567ฉันจะทำสิ่งนี้อย่างไร ฉันได้เห็นตัวอย่างมากมายใน Google แต่ฉันกำลังมองหาวิธีการปฏิบัติที่ง่ายที่สุด

ไม่จำเป็นต้องเป็นภาษาเฉพาะเพื่อตัดสินใจระหว่างช่วงเวลาและเครื่องหมายจุลภาค ฉันต้องการอะไรที่เรียบง่ายที่สุดเท่าที่จะทำได้

คำตอบ:


1738

สถานที่เกิดเหตุไม่รู้ตัว

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

ตระหนักถึงสถานที่

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

การอ้างอิง

ต่อข้อกำหนดรูปแบบมินิ - ภาษา ,

','ตัวเลือกที่จะส่งสัญญาณการใช้เครื่องหมายจุลภาคเพื่อคั่นหลักพัน สำหรับตัวคั่นที่รับรู้โลแคลให้ใช้'n'ชนิดงานนำเสนอจำนวนเต็มแทน


24
โปรดทราบว่าสิ่งนี้จะไม่ถูกต้องนอกสหรัฐอเมริกาและสถานที่อื่น ๆ ในกรณีนั้น locale.format () ที่เลือกเป็นคำตอบที่ถูกต้อง
Gringo Suave

11
รูปแบบอาร์กิวเมนต์ของคำหลัก:{val:,}.format(val=val)
CivFan

11
ขอบคุณมาก สำหรับจำนวนเงินที่มีทศนิยม 2 ตำแหน่ง - "{:,. 2f}". รูปแบบ (ค่า)
dlink

3
สำหรับโปรตุเกสที่เราใช้จุด (.) เป็นตัวคั่นเพียง: {:,} ". รูปแบบ (ค่า) .replace (',', '.')

13
ใน python 3.6 ขึ้นไป f-strings จะเพิ่มความสะดวก เช่นf"{2 ** 64 - 1:,}"
CJ Gaconnet

285

ฉันได้รับสิ่งนี้เพื่อทำงาน:

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

แน่นอนว่าคุณไม่ต้องการการสนับสนุนสากล แต่ชัดเจนกระชับและใช้ห้องสมุดในตัว

ปล. นั่น "% d" เป็นฟอร์แมตเตอร์% -style ปกติ คุณสามารถมีฟอร์แมตเตอร์เดียวได้ แต่อาจเป็นสิ่งที่คุณต้องการในแง่ของความกว้างของฟิลด์และการตั้งค่าความแม่นยำ

PPS หากคุณไม่สามารถlocaleทำงานได้ฉันขอแนะนำคำตอบของ 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)

การเรียกซ้ำมีประโยชน์สำหรับกรณีเชิงลบ แต่การเรียกซ้ำหนึ่งครั้งต่อคอมม่านั้นมากเกินไปสำหรับฉัน


14
ฉันลองใช้รหัสของคุณแล้ว แต่น่าเสียดายที่ฉันได้รับสิ่งนี้: "locale.Error: การตั้งค่าภาษาที่ไม่รองรับ" : -s
Mark Byers

11
ทำเครื่องหมาย: หากคุณอยู่บน Linux คุณอาจต้องการดูสิ่งที่อยู่ใน /etc/locale.gen ของคุณหรือสิ่งที่ glibc ของคุณใช้เพื่อสร้างสถานที่ คุณอาจต้องการลอง "" en "," en_US.utf8 "," en_US.UTF-8 ", 'en_UK" (sp?) ฯลฯ mikez: ต้องมีหนังสือ: "Dr. PEP: หรือ ฉันเรียนรู้ที่จะหยุดกังวลและรัก docs.python.org ได้อย่างไร " ฉันเลิกท่องจำไลบรารีทั้งหมดรอบ ๆ Python 1.5.6 สำหรับlocaleฉันฉันใช้มันให้น้อยที่สุดเท่าที่จะทำได้
Mike DeSimone

10
คุณสามารถใช้ '' setlocaleเพื่อใช้ค่าเริ่มต้นซึ่งหวังว่าจะเหมาะสม
Mark Ransom

24
ลองนี้: locale.setlocale (locale.LC_ALL, '') มันใช้งานได้สำหรับฉัน
Nadia Alramli

1
แม้ว่าจะฉลาด แต่ฉันไม่ชอบฟังก์ชั่นที่ทำการตั้งค่าทั่วโลก ... การใช้ 'blah'.format () เป็นวิธีที่ดีกว่า
Cerin

132

สำหรับความไม่มีประสิทธิภาพและอ่านไม่ได้ยากที่จะเอาชนะ:

>>> 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
โหวตวิธีที่ไม่มีประสิทธิภาพและอ่านไม่ได้ที่สุดเพื่อตอบคำถามนี้
psytek

1
จะดีถ้าอย่างน้อยก็จะได้ผล ลองใช้หมายเลขนี้ "17371830" มันจะกลายเป็น "173.718.3.0" =)
holms

5
ระยะเวลา? นั่นเป็นไปไม่ได้แม้แต่ holms ขยะชิ้นนี้ไม่สนใจสถานที่ ฉันสงสัยว่าคุณได้รับผลลัพธ์นั้นอย่างไร ตัวอย่างของคุณสร้าง '17, 371,830' สำหรับฉันตามที่คาดไว้
Kasey Kirkham

11
ในการทำให้ฟังก์ชั่นนี้เป็นสิ่งที่ฉันอยากจะแนะนำ: 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))เพียงแค่เก็บธีมที่ทำให้งงงวย
ควอนตัม

95

นี่คือรหัสการจัดกลุ่มโลแคลหลังจากลบส่วนที่ไม่เกี่ยวข้องออกและทำความสะอาดเล็กน้อย:

(ต่อไปนี้ใช้งานได้เฉพาะสำหรับจำนวนเต็ม)

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'

มีคำตอบที่ดีอยู่แล้วในที่นี้ ฉันแค่ต้องการเพิ่มสิ่งนี้เพื่อการอ้างอิงในอนาคต ใน python 2.7 จะมีตัวระบุรูปแบบสำหรับตัวคั่นหลักพัน ตามเอกสารของงูหลามมันใช้งานได้เช่นนี้

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

ใน python3.1 คุณสามารถทำสิ่งเดียวกันนี้:

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

ใช่วิธีที่ยากที่สุดสำหรับคนที่ใช้ Pythons รุ่นเก่าเช่นที่มาพร้อมกับ RHEL และ distros สนับสนุนระยะยาวอื่น ๆ
Mike DeSimone

3
วิธีแสดงสิ่งนี้ด้วยสตริงรูปแบบ? "%, d"% 1234567 ไม่ทำงาน
Frederic Bazin

92

ฉันประหลาดใจที่ไม่มีใครพูดถึงคุณสามารถทำได้ด้วย f-strings ใน Python 3.6 ง่ายเหมือนนี้:

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

... โดยที่ส่วนหลังโคลอนเป็นตัวระบุรูปแบบ เครื่องหมายจุลภาคเป็นตัวคั่นที่คุณต้องการดังนั้นf"{num:_}"ใช้เครื่องหมายขีดล่างแทนเครื่องหมายจุลภาค

สิ่งนี้เทียบเท่ากับการใช้งานformat(num, ",")กับงูหลาม 3 รุ่นเก่ากว่า


39

นี่คือการแทนที่ regex หนึ่งบรรทัด:

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

ใช้งานได้กับเอาต์พุต 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'

หรือสำหรับการลอยที่มีตัวเลขน้อยกว่า 4 หลักให้เปลี่ยนตัวระบุรูปแบบเป็น%.3f:

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

หมายเหตุ:ทำงานไม่ถูกต้องกับตัวเลขทศนิยมมากกว่าสามหลักเพราะจะพยายามจัดกลุ่มส่วนทศนิยม:

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

มันทำงานอย่างไร

มาทำลายมันกันเถอะ:

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
ใช้โหมด verbose และคุณสามารถแสดงความคิดเห็นได้ในโค้ด
Daniel Stracaboško

คุณไม่สามารถแทนที่ "(?! \ d)" ด้วย "$" หรือไม่
GL2014

28

นี่คือสิ่งที่ฉันทำเพื่อลอย แม้ว่าโดยแท้จริงแล้วฉันไม่แน่ใจว่าเวอร์ชันใดที่ใช้งานได้ - ฉันใช้ 2.7:

my_number = 4385893.382939491

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

คืนค่า: 4,385,893.38

อัปเดต: ฉันเพิ่งมีปัญหากับรูปแบบนี้ (ไม่สามารถบอกเหตุผลที่แน่นอนได้) แต่ก็สามารถแก้ไขได้ด้วยการวาง0:

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

19

คุณยังสามารถใช้'{:n}'.format( value )สำหรับการแสดงโลแคล ฉันคิดว่านี่เป็นวิธีที่ง่ายที่สุดสำหรับการแก้ปัญหาสถานที่

สำหรับข้อมูลเพิ่มเติมค้นหาthousandsในหลาม DOC

สำหรับสกุลเงินคุณสามารถใช้locale.currencyการตั้งค่าสถานะgrouping:

รหัส

import locale

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

เอาท์พุต

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

13

ขยายคำตอบของ Ian Schneider เล็กน้อย:

หากคุณต้องการใช้ตัวคั่นหลักพันแบบกำหนดเองโซลูชันที่ง่ายที่สุดคือ:

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

ตัวอย่าง

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

ถ้าคุณต้องการตัวแทนจากเยอรมันแบบนี้มันจะซับซ้อนกว่านี้เล็กน้อย:

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

สั้นลงเล็กน้อย:'{:_.2f}'.format(12345.6789).replace('.', ',').replace('_', '.')
Tom Pohl

12

ฉันแน่ใจว่าจะต้องมีฟังก์ชั่นไลบรารีมาตรฐานสำหรับสิ่งนี้ แต่มันสนุกที่จะพยายามเขียนด้วยตัวเองโดยใช้การเรียกซ้ำดังนั้นนี่คือสิ่งที่ฉันคิดขึ้นมา:

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)

ต้องบอกว่าถ้าคนอื่นหาวิธีมาตรฐานที่จะทำคุณควรใช้สิ่งนั้นแทน


น่าเสียดายที่ใช้ไม่ได้ในทุกกรณี intToStringWithCommas (1,000.1) -> '1.0001,000'
Nadia Alramli

เขาบอกว่าเป็นจำนวนเต็มโดยเฉพาะและมันควรจะง่ายที่สุดเท่าที่จะเป็นไปได้ดังนั้นฉันตัดสินใจที่จะไม่จัดการประเภทข้อมูลอื่นที่ไม่ใช่จำนวนเต็ม ฉันทำให้มันชัดเจนในชื่อฟังก์ชัน _int_ToStringWithCommas ตอนนี้ฉันได้เพิ่มการเพิ่มเพื่อให้ชัดเจนยิ่งขึ้น
Mark Byers

8

จากความคิดเห็นเพื่อเปิดใช้งานสูตร498181ฉันทำใหม่นี้:

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

จะใช้คุณสมบัติการแสดงออกปกติ: lookaheadคือ(?=\d)เพื่อให้แน่ใจว่าเฉพาะกลุ่มของตัวเลขสามหลักที่มีตัวเลข 'หลังจาก' พวกเขาได้รับเครื่องหมายจุลภาค ฉันพูดว่า 'after' เพราะสตริงกลับด้านตอนนี้

[::-1] เพียงแค่ย้อนกลับสตริง


8

คำตอบที่ได้รับการยอมรับอย่างดี format(number,',')แต่ผมชอบจริง ง่ายกว่าที่ฉันจะตีความและจดจำ

https://docs.python.org/3/library/functions.html#format


ทำงานได้อย่างสมบูรณ์และหลีกเลี่ยงการแสดงทศนิยมมากเกินไปสำหรับการลอย
Rexcirus

7

Python 3

-

จำนวนเต็ม (ไม่มีทศนิยม):

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

-

ลอย (พร้อมทศนิยม):

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

โดยที่ตัวเลขก่อนหน้านี้fระบุจำนวนตำแหน่งทศนิยม

-

โบนัส

ฟังก์ชันเริ่มต้นอย่างรวดเร็วและสกปรกสำหรับระบบหมายเลข lakhs / crores ของอินเดีย (12,34,567):

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


5

จาก Python เวอร์ชัน 2.6 คุณสามารถทำได้:

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

สำหรับ Python เวอร์ชัน <2.6 และสำหรับข้อมูลของคุณนี่คือโซลูชัน 2 แบบด้วยตนเองพวกมันเปลี่ยนเป็นแบบลอยตัว แต่เป็นตัวเลขลบทำงานอย่างถูกต้อง:

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)

สิ่งเล็ก ๆ น้อย ๆ ที่ควรสังเกตที่นี่:

  • บรรทัดนี้: string = '% d'% จำนวนแปลงตัวเลขเป็นสตริงได้อย่างสวยงามมันรองรับเนกาทีฟและหยดเศษส่วนจากโฟลตทำให้พวกมันเป็น ints;
  • ดัชนีชิ้นนี้[:: - 3]ส่งคืนแต่ละรายการที่สามเริ่มต้นจากจุดสิ้นสุดดังนั้นฉันจึงใช้อีกชิ้น[1:]เพื่อลบรายการสุดท้ายเพราะฉันไม่ต้องการเครื่องหมายจุลภาคหลังจากหมายเลขสุดท้าย;
  • เงื่อนไขนี้ถ้า l [index]! = '-'กำลังถูกใช้เพื่อรองรับจำนวนลบอย่าใส่เครื่องหมายจุลภาคหลังเครื่องหมายลบ

และเวอร์ชั่นฮาร์ดคอร์เพิ่มเติม:

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

ฉันเป็นผู้เริ่มต้น Python แต่เป็นโปรแกรมเมอร์ที่มีประสบการณ์ ฉันมี Python 3.5 ดังนั้นฉันจึงสามารถใช้เครื่องหมายจุลภาคได้ แต่นี่เป็นแบบฝึกหัดการเขียนโปรแกรมที่น่าสนใจ พิจารณากรณีของจำนวนเต็มไม่ได้ลงนาม โปรแกรม Python ที่อ่านได้ง่ายที่สุดสำหรับการเพิ่มตัวคั่นหลายพันตัวเป็นดังนี้

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)

นอกจากนี้ยังเป็นไปได้ที่จะใช้ list comprehension:

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)

สิ่งนี้สั้นกว่าและอาจเป็นหนึ่งสายการบิน แต่คุณจะต้องทำยิมนาสติกจิตเพื่อเข้าใจว่าทำไมมันถึงได้ผล ในทั้งสองกรณีเราได้รับ:

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

เวอร์ชันแรกเป็นตัวเลือกที่สมเหตุสมผลกว่าหากคุณต้องการให้โปรแกรมเข้าใจ


1

นี่คืออันที่ใช้ได้กับการลอยเช่นกัน:

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

ตัวอย่างการใช้งาน:

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

1
float2comma(12031023.1323)ส่งคืน: '12, 031,023.132,3 '
demux

1

หนึ่งซับสำหรับ Python 2.5+ และ Python 3 (บวก int เท่านั้น):

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

1

ทางออกสากล

ฉันพบปัญหาบางอย่างกับตัวแยกจุดในคำตอบที่ได้รับการโหวตสูงสุดก่อนหน้า ฉันได้รับการออกแบบการแก้ปัญหาสากลที่คุณสามารถใช้สิ่งที่คุณต้องการเป็นตัวคั่นพันโดยไม่ต้องปรับเปลี่ยนสถานที่เกิดเหตุ ฉันรู้ว่ามันไม่ใช่ทางออกที่หรูหราที่สุด แต่มันก็ทำงานได้สำเร็จ อย่าลังเลที่จะปรับปรุงมัน!

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

นี่ทำเงินพร้อมกับคอมม่า

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

ฉันมี python 2 และ python 3 เวอร์ชันของรหัสนี้ ฉันรู้ว่าคำถามถูกถามสำหรับ python 2 แต่ตอนนี้ (8 ปีต่อมาฮ่า ๆ ) ผู้คนอาจจะใช้ python 3

Python 3 Code:

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 Code: (แก้ไขรหัส python 2 ใช้งานไม่ได้ฉันคิดว่าซินแท็กซ์ต่างกัน)

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

ฉันใช้ python 2.5 ดังนั้นฉันจึงไม่สามารถเข้าถึงการจัดรูปแบบในตัวได้

ฉันดูที่โค้ด Django intcomma (intcomma_recurs ในโค้ดด้านล่าง) และรู้ว่ามันไม่มีประสิทธิภาพเพราะมันเรียกซ้ำและคอมไพล์ regex ในการรันทุกครั้งก็ไม่ได้เป็นสิ่งที่ดีเช่นกัน นี่ไม่จำเป็นต้องเป็น 'ปัญหา' เนื่องจาก django ไม่ใช่ที่มุ่งเน้นไปที่ประสิทธิภาพระดับต่ำแบบนี้ นอกจากนี้ฉันยังคาดหวังว่าปัจจัยที่มีความแตกต่างในการแสดงจะแตกต่างกันถึง 10 เท่า แต่มันช้าลงเพียง 3 ครั้งเท่านั้น

จากความอยากรู้อยากเห็นฉันนำอินทรามาสองสามเวอร์ชันมาใช้เพื่อดูว่าข้อได้เปรียบด้านประสิทธิภาพคืออะไรเมื่อใช้ regex ข้อมูลการทดสอบของฉันสรุปว่าเป็นข้อได้เปรียบเล็กน้อยสำหรับงานนี้ แต่ก็ไม่แปลกใจเท่าไหร่

ฉันก็ยินดีที่ได้เห็นสิ่งที่ฉันสงสัย: การใช้ reverse xrange เป็นสิ่งที่ไม่จำเป็นในกรณีที่ไม่มี regex แต่มันทำให้โค้ดดูดีขึ้นเล็กน้อยในราคาประมาณ 10% ของประสิทธิภาพ

นอกจากนี้ฉันคิดว่าสิ่งที่คุณกำลังผ่านเป็นสตริงและมีลักษณะค่อนข้างเป็นตัวเลข ผลลัพธ์ที่ไม่ได้ระบุไว้เป็นอย่างอื่น

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

และนี่คือผลการทดสอบ:

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

ฉันคิดว่าโซลูชัน one-regex ของ Daniel Fortunov น่าจะเป็นอันดับ 1 และเอาชนะอัลกอริธึมทั้งหมดเพราะ regex นั้นได้รับการปรับปรุง / ปรับให้เหมาะสมและเขียนโค้ดใน C แต่ไม่ใช่ .. ฉันเดาว่ารูปแบบและ lookahead นั้นแพงเกินไป มันอยู่ในเวลาประมาณสองเท่าของคอมมานด์ข้างบนแม้จะมีการคอมไพล์ regex ล่วงหน้า
parity3

0

สิ่งนี้ถูกอบเข้า python ต่อ PEP -> https://www.python.org/dev/peps/pep-0378/

เพียงใช้รูปแบบ (1,000, ', d') เพื่อแสดงจำนวนเต็มพร้อมตัวคั่นหลักพัน

มีรูปแบบเพิ่มเติมที่อธิบายไว้ใน PEP มีที่มัน


-1

นี่คืออีกตัวแปรหนึ่งที่ใช้ฟังก์ชันตัวสร้างที่ทำงานกับจำนวนเต็ม:

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

และนี่คือการทดสอบ:

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

เพียงคลาสย่อยlong( floatหรืออะไรก็ตาม) นี่เป็นประโยชน์อย่างมากเพราะวิธีนี้คุณยังสามารถใช้ตัวเลขของคุณในคณิตศาสตร์ ops (และรหัสที่มีอยู่) แต่พวกเขาทั้งหมดจะพิมพ์อย่างใน 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
ฉันชอบแนวคิดของคลาสย่อย แต่เป็น__repr__()วิธีที่ถูกต้องในการแทนที่หรือไม่ ฉันจะแนะนำให้เอาชนะ__str__()และออกจาก__repr__()คนเดียวเพราะint(repr(number(928374)))ควรจะทำงาน แต่int()จะสำลักในเครื่องหมายจุลภาค
steveha

@steveha มีจุดดี แต่เหตุผลที่ควรจะได้รับการที่ไม่ได้ทำงานไม่ได้number(repr(number(928374))) int(repr(number(928374)))ทั้งหมดเดียวกันเพื่อให้การทำงานวิธีการนี้โดยตรงกับprintเป็น OP ที่มีการร้องขอที่วิธีการที่ควรจะเป็นหนึ่งแทนที่มากกว่า__str__() __repr__()ดูเหมือนว่าจะมีข้อผิดพลาดในตรรกะการแทรกเครื่องหมายจุลภาคหลัก
martineau


-8

สำหรับลอยตัว:

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

สำหรับ ints:

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

5
ที่ลบเครื่องหมายจุลภาค ในขณะที่มีประโยชน์ OP ขอวิธีการที่จะเพิ่มพวกเขา นอกจากนี้สิ่งที่ชอบfloat('1,234.52'.translate(None, ','))อาจตรงไปตรงมาและเร็วขึ้น
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.