Sola sıfırları olan sayısal bir dizeyi doldurmanın Pythonic yolu nedir, yani sayısal dizenin belirli bir uzunluğu vardır?
Sola sıfırları olan sayısal bir dizeyi doldurmanın Pythonic yolu nedir, yani sayısal dizenin belirli bir uzunluğu vardır?
Yanıtlar:
Teller:
>>> n = '4'
>>> print(n.zfill(3))
004
Ve sayılar için:
>>> 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
yanlış. Bu sözdizimi çalışmaz python >= 3
. Bunu şu şekilde değiştirebilirsiniz python < 3
, ancak bunun yerine her zaman parantez kullanmanızı ve yorumları tamamen atlamayı önerebilir miyim (önerilen kullanımı teşvik eder)?
'{:03d} {:03d}'.format(1, 2)
değerleri sırayla sırayla atar.
print
ne zaman bir print
fonksiyon olmalı ? Ben ebeveynlerde kurguladım; sadece bir şey basıldığından, şimdi Py2 ve Py3 üzerinde aynı şekilde çalışır.
String nesnesinin rjust yöntemini kullanmanız yeterlidir .
Bu örnek, gerektiği gibi dolgu yaparak 10 karakter uzunluğunda bir dize oluşturur.
>>> t = 'test'
>>> t.rjust(10, '0')
>>> '000000test'
Ayrıca zfill
, genel dize biçimlendirmesini kullanabilirsiniz:
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'))
Dize biçimlendirme ve f-dizeleri belgeleri .
format
bunun yerine kullanıldığını söylüyor ve insanlar bunu genellikle itiraz etme niyeti olarak yorumluyorlar.
F-stringleri kullanan Python 3.6+ için:
>>> i = 1
>>> f"{i:0>2}" # Works for both numbers and strings.
'01'
>>> f"{i:02}" # Works only for numbers.
'01'
Python 2 - Python 3.5 için:
>>> "{: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'
tam tersini istiyorsanız:
>>> '99'.ljust(5,'0')
'99000'
Buraya gelenler için sadece hızlı bir cevap değil, anlamak. Bunları özellikle zaman dizeleri için yapıyorum:
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", "2" dolgu karakterleriyle değiştirilecek sembolleri belirtir, varsayılan değer boş bir alandır
">" simgeleri dizenin solundaki 2 "0" karakterin tümünü hizalar
":" format_spec semboller
Sayısal bir dizgiyi sola sıfırla doldurmanın en pythonic yolu nedir, yani sayısal dizginin belirli bir uzunluğu vardır?
str.zfill
özellikle bunu yapmak için tasarlanmıştır:
>>> '1'.zfill(4)
'0001'
Özellikle sayısal dizeleri istendiği gibi işlemenin amaçlandığını ve dizenin başına a +
veya -
başlangıcını taşıdığını unutmayın :
>>> '+1'.zfill(4)
'+001'
>>> '-1'.zfill(4)
'-001'
İşte yardım 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.
Bu aynı zamanda alternatif yöntemlerin en performansıdır:
>>> 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
%
Yöntem için elmaları elmalarla en iyi şekilde karşılaştırmak için (aslında daha yavaş olduğuna dikkat edin), aksi takdirde ön hesaplama yapar:
>>> min(timeit.repeat(lambda: '1'.zfill(0 or 4)))
0.19728074967861176
>>> min(timeit.repeat(lambda: '%04d' % (0 or 1)))
0.2347015216946602
Biraz kazma ile, zfill
yöntemin uygulanmasını şu şekilde buldum 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;
}
Bu C kodunu inceleyelim.
Önce argümanı konumsal olarak ayrıştırır, yani anahtar kelime argümanlarına izin vermez:
>>> '1'.zfill(width=4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: zfill() takes no keyword arguments
Daha sonra aynı uzunluk veya daha uzun olup olmadığını kontrol eder, bu durumda dizeyi döndürür.
>>> '1'.zfill(0)
'1'
zfill
çağrıları pad
(bu pad
fonksiyonu da adlandırılır ljust
, rjust
ve center
hem de). Bu temelde içeriği yeni bir dizeye kopyalar ve dolguyu doldurur.
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;
}
Arama yaptıktan sonra pad
, zfill
orijinal olarak önceki +
veya -
dizenin başına gider .
Orijinal dizenin gerçekte sayısal olması gerekmediğini unutmayın:
>>> '+foo'.zfill(10)
'+000000foo'
>>> '-foo'.zfill(10)
'-000000foo'
+
ve -
ve ben dokümanlar için bir bağlantı eklendi!
width = 10
x = 5
print "%0*d" % (width, x)
> 0000000005
Tüm heyecan verici ayrıntılar için basılı belgelere bakın!
Python 3.x güncellemesi (7.5 yıl sonra)
Bu son satır şu şekilde olmalıdır:
print("%0*d" % (width, x))
Yani print()
artık bir işlev, bir ifade değil. Hala Old School printf()
stilini tercih ettiğime dikkat edin, çünkü IMNSHO, daha iyi okuyor ve çünkü, o gösterimi Ocak 1980'den beri kullanıyorum. Bir şey ... yaşlı köpekler .. bir şey ... yeni numaralar.
"%0*d" % (width, x)
python tarafından nasıl yorumlandığına dair daha fazla açıklama yapabilir misiniz ?
Python kullanırken >= 3.6
, en temiz yolu kullanmaktır f-dizeleri ile dize biçimlendirme :
>>> 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'
int
Ancak o zaman işareti doğru işlenir, çünkü biçimlendirme tercih ederim :
>>> f"{-1:08}"
'-0000001'
>>> f"{1:+08}"
'+0000001'
>>> f"{'-1':0>8}"
'000000-1'
Hızlı zamanlama karşılaştırması:
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]
Farklı tekrarlar için farklı testler yaptım. Farklılıklar çok büyük değil, ancak tüm testlerde zfill
çözüm en hızlıydı.
Başka bir yaklaşım, uzunlukları kontrol eden bir durumla birlikte bir liste kavrayışı kullanmak olacaktır. Aşağıda bir gösteri:
# 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']
Ayrıca "0" karakterini tekrarlayabilir, başına ekleyebilir str(n)
ve en sağdaki dilimi alabilirsiniz. Hızlı ve kirli küçük ifade.
def pad_left(n, width, pad="0"):
return ((pad * width) + str(n))[-width:]