Apa yang dimaksud dengan cara Pythonic untuk mengisi string numerik dengan nol di sebelah kiri, sehingga string numerik memiliki panjang tertentu?
Apa yang dimaksud dengan cara Pythonic untuk mengisi string numerik dengan nol di sebelah kiri, sehingga string numerik memiliki panjang tertentu?
Jawaban:
String:
>>> n = '4'
>>> print(n.zfill(3))
004
Dan untuk angka:
>>> n = 4
>>> print(f'{n:03}') # Preferred method, python >= 3.6
004
>>> 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
python >= 2.6
salah. Sintaks itu tidak berfungsi python >= 3
. Anda dapat mengubahnya python < 3
, tetapi bolehkah saya menyarankan untuk selalu menggunakan tanda kurung dan menghilangkan komentar sama sekali (mendorong penggunaan yang disarankan)?
'{:03d} {:03d}'.format(1, 2)
secara implisit memberikan nilai-nilai secara berurutan.
print
pernyataan itu, padahal seharusnya print
fungsi pada Python 3? Saya mengedit di parens; karena hanya satu hal yang sedang dicetak, ia bekerja secara identik sekarang di Py2 dan Py3.
Cukup gunakan metode rjust dari objek string.
Contoh ini akan membuat string sepanjang 10 karakter, padding sesuai kebutuhan.
>>> t = 'test'
>>> t.rjust(10, '0')
>>> '000000test'
Selain itu zfill
, Anda dapat menggunakan pemformatan string umum:
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'))
Dokumentasi untuk pemformatan string dan f-string .
format
sebagai gantinya, dan orang-orang umumnya menafsirkan ini sebagai niat untuk mundur.
Untuk Python 3.6+ menggunakan f-string:
>>> i = 1
>>> f"{i:0>2}" # Works for both numbers and strings.
'01'
>>> f"{i:02}" # Works only for numbers.
'01'
Untuk Python 2 hingga Python 3.5:
>>> "{:0>2}".format("1") # Works for both numbers and strings.
'01'
>>> "{:02}".format(1) # Works only for numbers.
'01'
>>> '99'.zfill(5)
'00099'
>>> '99'.rjust(5,'0')
'00099'
jika Anda menginginkan yang sebaliknya:
>>> '99'.ljust(5,'0')
'99000'
Bagi mereka yang datang ke sini untuk mengerti dan bukan hanya jawaban cepat. Saya melakukan ini terutama untuk string waktu:
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<3}:{:0<5}".format(hour,minute)
# prints '400:30000'
"{:$<3}:{:#<5}".format(hour,minute)
# prints '4$$:3####'
"0" melambangkan apa yang harus diganti dengan karakter padding "2", standarnya adalah ruang kosong
">" simbol mengatur semua karakter 2 "0" di sebelah kiri string
":" melambangkan format_spec
Apa cara paling pythonic untuk mengisi string numerik dengan nol ke kiri, yaitu, sehingga string numerik memiliki panjang tertentu?
str.zfill
secara khusus dimaksudkan untuk melakukan ini:
>>> '1'.zfill(4)
'0001'
Perhatikan bahwa ini secara khusus dimaksudkan untuk menangani string numerik seperti yang diminta, dan memindahkan a +
atau -
ke awal string:
>>> '+1'.zfill(4)
'+001'
>>> '-1'.zfill(4)
'-001'
Inilah bantuan untuk 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.
Ini juga yang paling banyak melakukan metode alternatif:
>>> 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
Untuk membandingkan apel dengan apel untuk %
metode ini (perhatikan bahwa sebenarnya lebih lambat), yang sebaliknya akan melakukan pra-perhitungan:
>>> min(timeit.repeat(lambda: '1'.zfill(0 or 4)))
0.19728074967861176
>>> min(timeit.repeat(lambda: '%04d' % (0 or 1)))
0.2347015216946602
Dengan sedikit penggalian, saya menemukan implementasi zfill
metode di Objects/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;
}
Mari kita telusuri kode C ini.
Pertama mem-parsing argumen secara posisi, artinya tidak mengizinkan argumen kata kunci:
>>> '1'.zfill(width=4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: zfill() takes no keyword arguments
Itu kemudian memeriksa apakah itu panjang yang sama atau lebih lama, dalam hal ini mengembalikan string.
>>> '1'.zfill(0)
'1'
zfill
panggilan pad
(ini pad
fungsi disebut juga dengan ljust
, rjust
, dan center
juga). Ini pada dasarnya menyalin konten ke string baru dan mengisi 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;
}
Setelah memanggil pad
, zfill
pindahkan semua yang awalnya sebelum +
atau -
ke awal string.
Perhatikan bahwa untuk string asli menjadi numerik tidak diperlukan:
>>> '+foo'.zfill(10)
'+000000foo'
>>> '-foo'.zfill(10)
'-000000foo'
+
dan -
, dan saya menambahkan tautan ke dokumen!
width = 10
x = 5
print "%0*d" % (width, x)
> 0000000005
Lihat dokumentasi cetak untuk semua detail menarik!
Pembaruan untuk Python 3.x (7,5 tahun kemudian)
Baris terakhir itu sekarang adalah:
print("%0*d" % (width, x))
Yaitu print()
sekarang fungsi, bukan pernyataan. Perhatikan bahwa saya masih lebih suka printf()
gaya Sekolah Lama karena, IMNSHO, bunyinya lebih baik, dan karena, um, saya telah menggunakan notasi itu sejak Januari 1980. Sesuatu ... anjing-anjing tua ... sesuatu yang ... trik-trik baru.
"%0*d" % (width, x)
ditafsirkan oleh python?
Saat menggunakan Python >= 3.6
, cara terbersih adalah menggunakan f-string dengan pemformatan string :
>>> s = f"{1:08}" # inline with int
>>> s
'00000001'
>>> s = f"{'1':0>8}" # inline with str
>>> s
'00000001'
>>> n = 1
>>> s = f"{n:08}" # int variable
>>> s
'00000001'
>>> c = "1"
>>> s = f"{c:0>8}" # str variable
>>> s
'00000001'
Saya lebih suka memformat dengan int
, karena hanya saat itu tanda ditangani dengan benar:
>>> f"{-1:08}"
'-0000001'
>>> f"{1:+08}"
'+0000001'
>>> f"{'-1':0>8}"
'000000-1'
Perbandingan waktu cepat:
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]
Saya telah membuat berbagai tes pengulangan yang berbeda. Perbedaannya tidak besar, tetapi dalam semua tes, zfill
solusinya paling cepat.
Pendekatan lain adalah dengan menggunakan pemahaman daftar dengan kondisi memeriksa panjang. Di bawah ini adalah demonstrasi:
# 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']
Anda juga bisa mengulangi "0", tambahkan dulu str(n)
dan dapatkan irisan lebar paling kanan. Ekspresi kecil yang cepat dan kotor.
def pad_left(n, width, pad="0"):
return ((pad * width) + str(n))[-width:]