Mai frumos mod de a pad zerouri la un șir

Ceea ce este cel mai Pythonic mod de a pad numeric șir cu zerouri la stânga, adică, atât numeric șir are o anumită lungime?

Soluția

Siruri de caractere:

>>> n = '4'
>>> print(n.zfill(3))
004

Și pentru numere:

>>> n = 4
>>> print('%03d' % n)
004
>>> print(format(n, '03')) # python >= 2.6
004
>>> print('{0:03d}'.format(n))  # python >= 2.6 + python 3
004
>>> print('{foo:03d}'.format(foo=n))  # python >= 2.6 + python 3
004
>>> print('{:03d}'.format(n))  # python >= 2.7 + python3
004
>>> print(f'{n:03}') # python >= 3.6
004

Șir de formatare documentația.

Comentarii (8)

Doar folosi rjust metoda de obiect string.

Acest exemplu va face un șir de 10 caractere, umplutură după cum este necesar.

>>> t = 'test'
>>> t.rjust(10, '0')
>>> '000000test'
Comentarii (0)

În afară de zfill, puteți utiliza general șir de formatare:

print(f'{number:05d}') # (since Python 3.6), or
print('{:05d}'.format(number)) # or
print('{0:05d}'.format(number)) # or (explicit 0th positional arg. selection)
print('{n:05d}'.format(n=number)) # or (explicit `n` keyword arg. selection)
print(format(number, '05d'))

Documentația pentru șir de formatare și f-siruri de caractere.

Comentarii (10)

Acest lucru funcționează în ambele Python 2 și 3 Python:

>>> "{:0>2}".format("1")  # Works for both numbers and strings.
'01'
>>> "{:02}".format(1)  # Works only for numbers.
'01'

Pentru utilizarea cu Python 3.6+ folosind f-siruri de caractere:

>>> i = 1
>>> f"{i:0>2}"  # Works for both numbers and strings.
'01'
>>> f"{i:02}"  # Works only for numbers.
'01'
Comentarii (0)
>>> '99'.zfill(5)
'00099'
>>> '99'.rjust(5,'0')
'00099'

dacă doriți opus:

>>> '99'.ljust(5,'0')
'99000'
Comentarii (0)

str(n).zfill(lățime) va lucra cu strings, int i, `float... și este Python 2.x și 3.x compatibil:

>>> n = 3
>>> str(n).zfill(5)
'00003'
>>> n = '3'
>>> str(n).zfill(5)
'00003'
>>> n = '3.0'
>>> str(n).zfill(5)
'003.0'
Comentarii (0)

Pentru cei care au venit aici pentru a înțelege și nu doar un răspuns rapid.

  • Aș face-o în special pentru siruri de caractere:

hour = 4
minute = 3
"{:0>2}:{:0>2}".format(hour,minute)
# prints 04:03

"{:0>3}:{:0>5}".format(hour,minute)
# prints '004:00003'

"{:0
Comentarii (0)

ceea Ce este cel mai pythonic mod de a pad numeric șir cu zerouri la stânga, adică, atât numeric șir are o anumită lungime?

str.zfill este special destinat pentru a face acest lucru:

>>> '1'.zfill(4)
'0001'

Rețineți că acesta este destinat în mod special să se ocupe numerice, siruri de caractere cum a solicitat, și se mută un " + " sau " - " la începutul șirului:

>>> '+1'.zfill(4)
'+001'
>>> '-1'.zfill(4)
'-001'

Aici's a ajuta pe str.zfill`:

>>> help(str.zfill)
Help on method_descriptor:

zfill(...)
    S.zfill(width) -> str

    Pad a numeric string S with zeros on the left, to fill a field
    of the specified width. The string S is never truncated.

De performanță

Acest lucru este, de asemenea, cele mai performante metode alternative:

>>> min(timeit.repeat(lambda: '1'.zfill(4)))
0.18824880896136165
>>> min(timeit.repeat(lambda: '1'.rjust(4, '0')))
0.2104538488201797
>>> min(timeit.repeat(lambda: f'{1:04}'))
0.32585487607866526
>>> min(timeit.repeat(lambda: '{:04}'.format(1)))
0.34988890308886766

Pentru mai compara mere cu mere pentru % metoda (rețineți că este de fapt mai lent), care, altfel, se va pre-calcula:

>>> min(timeit.repeat(lambda: '1'.zfill(0 or 4)))
0.19728074967861176
>>> min(timeit.repeat(lambda: '%04d' % (0 or 1)))
0.2347015216946602

Punerea în aplicare

Cu un pic de sapaturi, am gasit punerea în aplicare a zfill metoda din Obiecte/stringlib/transmogrify.h:

static PyObject *
stringlib_zfill(PyObject *self, PyObject *args)
{
    Py_ssize_t fill;
    PyObject *s;
    char *p;
    Py_ssize_t width;

    if (!PyArg_ParseTuple(args, "n:zfill", &width))
        return NULL;

    if (STRINGLIB_LEN(self) >= width) {
        return return_self(self);
    }

    fill = width - STRINGLIB_LEN(self);

    s = pad(self, fill, 0, '0');

    if (s == NULL)
        return NULL;

    p = STRINGLIB_STR(s);
    if (p[fill] == '+' || p[fill] == '-') {
        /* move sign to beginning of string */
        p[0] = p[fill];
        p[fill] = '0';
    }

    return s;
}

Las's de mers pe jos prin acest cod C.

Primul analizează argument pozițional, ceea ce înseamnă că nu't permite cuvinte cheie argumente:

>>> '1'.zfill(width=4)
Traceback (most recent call last):
  File "", line 1, in 
TypeError: zfill() takes no keyword arguments

Se verifică apoi dacă-l's de aceeași lungime sau mai mult, caz în care se returnează șirul.

>>> '1'.zfill(0)
'1'

zfill telefoane pad (asta pad funcția este, de asemenea, numit de eu, rjust, și "centru", la fel de bine). Acest fapt copiază conținutul într-un nou șir și umple padding.

static inline PyObject *
pad(PyObject *self, Py_ssize_t left, Py_ssize_t right, char fill)
{
    PyObject *u;

    if (left < 0)
        left = 0;
    if (right < 0)
        right = 0;

    if (left == 0 && right == 0) {
        return return_self(self);
    }

    u = STRINGLIB_NEW(NULL, left + STRINGLIB_LEN(self) + right);
    if (u) {
        if (left)
            memset(STRINGLIB_STR(u), fill, left);
        memcpy(STRINGLIB_STR(u) + left,
               STRINGLIB_STR(self),
               STRINGLIB_LEN(self));
        if (right)
            memset(STRINGLIB_STR(u) + left + STRINGLIB_LEN(self),
                   fill, right);
    }

    return u;
}

După apelarea pad, zfill se mișcă în orice inițial precedente " + " sau " - " la începutul șirului.

Rețineți că pentru șirul inițial pentru a fi de fapt numerică nu este necesară:

>>> '+foo'.zfill(10)
'+000000foo'
>>> '-foo'.zfill(10)
'-000000foo'
Comentarii (2)
width = 10
x = 5
print "%0*d" % (width, x)
> 0000000005

Vezi de imprimare a documentației pentru toate detaliile interesante!

Actualizare pentru Python 3.x (7,5 ani mai târziu)

Ultima linie ar trebui să fie acum:

print("%0*d" % (width, x))

I. e. print() este acum o funcție, nu o declarație. Rețineți că eu încă prefer Old School `printf () "stil" pentru că, IMNSHO, se citește mai bine, și pentru că am'am fost folosind această notație din ianuarie, 1980. Ceva ... câinii bătrâni .. ceva ceva ... trucuri noi.

Comentarii (1)

Atunci când se utilizează Python >= 3.6, cel mai curat mod este de a utiliza f-siruri de caractere cu șir de caractere format caietul de sarcini:

>>> s = f"{1:08}"  # inline with int constant
>>> s
'00000001'
>>> n = 1
>>> s = f"{n:08}"  # int variable
>>> s
'00000001'
>>> c = "1"
>>> s = f"{c:0>8}"  # str variable
>>> s
'00000001'
Comentarii (0)

Pentru zip coduri memorate ca numere întregi:

>>> a = 6340
>>> b = 90210
>>> print '%05d' % a
06340
>>> print '%05d' % b
90210
Comentarii (3)

Sincronizare rapid comparație:

setup = '''
from random import randint
def test_1():
    num = randint(0,1000000)
    return str(num).zfill(7)
def test_2():
    num = randint(0,1000000)
    return format(num, '07')
def test_3():
    num = randint(0,1000000)
    return '{0:07d}'.format(num)
def test_4():
    num = randint(0,1000000)
    return format(num, '07d')
def test_5():
    num = randint(0,1000000)
    return '{:07d}'.format(num)
def test_6():
    num = randint(0,1000000)
    return '{x:07d}'.format(x=num)
def test_7():
    num = randint(0,1000000)
    return str(num).rjust(7, '0')
'''
import timeit
print timeit.Timer("test_1()", setup=setup).repeat(3, 900000)
print timeit.Timer("test_2()", setup=setup).repeat(3, 900000)
print timeit.Timer("test_3()", setup=setup).repeat(3, 900000)
print timeit.Timer("test_4()", setup=setup).repeat(3, 900000)
print timeit.Timer("test_5()", setup=setup).repeat(3, 900000)
print timeit.Timer("test_6()", setup=setup).repeat(3, 900000)
print timeit.Timer("test_7()", setup=setup).repeat(3, 900000)

> [2.281613943830961, 2.2719342631547077, 2.261691106209631]
> [2.311480238815406, 2.318420542148333, 2.3552384305184493]
> [2.3824197456864304, 2.3457239951596485, 2.3353268829498646]
> [2.312442972404032, 2.318053102249902, 2.3054072168069872]
> [2.3482314132374853, 2.3403386400002475, 2.330108825844775]
> [2.424549090688892, 2.4346475296851438, 2.429691196530058]
> [2.3259756401716487, 2.333549212826732, 2.32049893822186]

Am'am facut diferite teste de diferite repetiții. Diferențele nu sunt foarte mari, dar in toate testele, `zfill soluție a fost mai rapid.

Comentarii (0)

O altă abordare ar fi de a utiliza o listă de înțelegere cu condiția de verificare pentru lungimi. Mai jos este o demonstratie:

# input list of strings that we want to prepend zeros
In [71]: list_of_str = ["101010", "10101010", "11110", "0000"]

# prepend zeros to make each string to length 8, if length of string is less than 8
In [83]: ["0"*(8-len(s)) + s if len(s) < desired_len else s for s in list_of_str]
Out[83]: ['00101010', '10101010', '00011110', '00000000']
Comentarii (0)

Ai putea repeta, de asemenea, "0", adauga-l la `str(n) și obține din dreapta latime felie. Rapid și murdar pic de exprimare.

def pad_left(n, width, pad="0"):
    return ((pad * width) + str(n))[-width:]
Comentarii (2)