Cách Pythonic để đệm một chuỗi số có số 0 ở bên trái, nghĩa là chuỗi số có độ dài cụ thể?
Cách Pythonic để đệm một chuỗi số có số 0 ở bên trái, nghĩa là chuỗi số có độ dài cụ thể?
Câu trả lời:
Dây:
>>> n = '4'
>>> print(n.zfill(3))
004
Và cho số:
>>> 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
không chính xác. Cú pháp đó không hoạt động python >= 3
. Bạn có thể thay đổi nó thành python < 3
, nhưng tôi có thể đề nghị thay vì luôn luôn sử dụng dấu ngoặc đơn và bỏ hoàn toàn các nhận xét (khuyến khích sử dụng được khuyến nghị) không?
'{:03d} {:03d}'.format(1, 2)
ngầm định gán các giá trị theo thứ tự.
print
câu lệnh, khi nào nó phải là một print
hàm trên Python 3? Tôi đã chỉnh sửa trong parens; vì chỉ có một thứ đang được in, nên nó hoạt động giống hệt trên Py2 và Py3.
Chỉ cần sử dụng rjust phương pháp của đối tượng chuỗi.
Ví dụ này sẽ tạo một chuỗi dài 10 ký tự, đệm khi cần thiết.
>>> t = 'test'
>>> t.rjust(10, '0')
>>> '000000test'
Ngoài ra zfill
, bạn có thể sử dụng định dạng chuỗi chung:
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'))
Tài liệu cho định dạng chuỗi và chuỗi f .
format
thay thế và mọi người thường hiểu đây là ý định phản đối.
Đối với Python 3.6+ sử dụng chuỗi f:
>>> i = 1
>>> f"{i:0>2}" # Works for both numbers and strings.
'01'
>>> f"{i:02}" # Works only for numbers.
'01'
Đối với Python 2 đến 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'
nếu bạn muốn ngược lại:
>>> '99'.ljust(5,'0')
'99000'
Đối với những người đến đây để hiểu và không chỉ là một câu trả lời nhanh chóng. Tôi làm những điều này đặc biệt cho các chuỗi thời gian:
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####'
Ký hiệu "0" cần thay thế bằng ký tự đệm "2", mặc định là khoảng trống
Các ký hiệu ">" sắp xếp tất cả các ký tự 2 "0" ở bên trái chuỗi
":" ký hiệu format_spec
Cách pythonic nhất để đệm một chuỗi số có số 0 ở bên trái, nghĩa là, chuỗi số có độ dài cụ thể là gì?
str.zfill
được dành riêng để làm điều này:
>>> '1'.zfill(4)
'0001'
Lưu ý rằng nó được dành riêng để xử lý các chuỗi số theo yêu cầu và di chuyển một +
hoặc -
đến đầu chuỗi:
>>> '+1'.zfill(4)
'+001'
>>> '-1'.zfill(4)
'-001'
Đây là sự giúp đỡ về 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.
Đây cũng là cách hiệu quả nhất của các phương pháp thay thế:
>>> 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
Để so sánh tốt nhất táo với táo cho %
phương pháp (lưu ý rằng nó thực sự chậm hơn), nếu không sẽ tính toán trước:
>>> min(timeit.repeat(lambda: '1'.zfill(0 or 4)))
0.19728074967861176
>>> min(timeit.repeat(lambda: '%04d' % (0 or 1)))
0.2347015216946602
Với một chút đào, tôi tìm thấy việc thực hiện zfill
phương pháp trong 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;
}
Hãy đi qua mã C này.
Đầu tiên, nó phân tích cú pháp đối số theo vị trí, nghĩa là nó không cho phép đối số từ khóa:
>>> '1'.zfill(width=4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: zfill() takes no keyword arguments
Sau đó, nó kiểm tra xem nó có cùng độ dài hoặc dài hơn không, trong trường hợp đó nó trả về chuỗi.
>>> '1'.zfill(0)
'1'
zfill
cuộc gọi pad
(điều này pad
chức năng cũng được gọi bằng ljust
, rjust
và center
cũng). Điều này về cơ bản sao chép nội dung thành một chuỗi mới và điền vào phần đệm.
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;
}
Sau khi gọi pad
, zfill
di chuyển bất kỳ trước đó ban đầu +
hoặc -
đến đầu chuỗi.
Lưu ý rằng để chuỗi gốc thực sự là số là không bắt buộc:
>>> '+foo'.zfill(10)
'+000000foo'
>>> '-foo'.zfill(10)
'-000000foo'
+
và -
, và tôi đã thêm một liên kết đến các tài liệu!
width = 10
x = 5
print "%0*d" % (width, x)
> 0000000005
Xem tài liệu in cho tất cả các chi tiết thú vị!
Cập nhật cho Python 3.x (7.5 năm sau)
Dòng cuối cùng bây giờ sẽ là:
print("%0*d" % (width, x))
Tức print()
là bây giờ là một chức năng, không phải là một tuyên bố. Lưu ý rằng tôi vẫn thích printf()
phong cách Trường học cũ bởi vì, IMNSHO, nó đọc tốt hơn và bởi vì, ừm, tôi đã sử dụng ký hiệu đó từ tháng 1 năm 1980. Một cái gì đó ... những con chó cũ .. một cái gì đó ... thủ thuật mới.
"%0*d" % (width, x)
giải thích của python không?
Khi sử dụng Python >= 3.6
, cách sạch nhất là sử dụng chuỗi f với định dạng chuỗi :
>>> 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'
Tôi muốn định dạng với một int
, vì chỉ sau đó dấu hiệu được xử lý chính xác:
>>> f"{-1:08}"
'-0000001'
>>> f"{1:+08}"
'+0000001'
>>> f"{'-1':0>8}"
'000000-1'
So sánh thời gian nhanh:
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]
Tôi đã thực hiện các thử nghiệm khác nhau về sự lặp lại khác nhau. Sự khác biệt không lớn, nhưng trong tất cả các thử nghiệm, zfill
giải pháp là nhanh nhất.
Một cách tiếp cận khác là sử dụng một sự hiểu biết danh sách với một điều kiện kiểm tra độ dài. Dưới đây là một minh chứng:
# 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']
Bạn cũng có thể lặp lại "0", thêm nó vào str(n)
và lấy lát cắt có chiều rộng ngoài cùng bên phải. Nhanh và bẩn ít biểu hiện.
def pad_left(n, width, pad="0"):
return ((pad * width) + str(n))[-width:]