Bir dizeye sıfırlar nasıl eklenir?


1445

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:


2393

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

Dize biçimlendirme belgeleri .


3
'Float' türündeki nesne için bilinmeyen biçim kodu 'd'.
Cees Timmerman

7
Yorumlar python >= 2.6yanlış. 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)?
Jason

4
Biçim dizelerinizi numaralandırmanıza gerek olmadığını unutmayın: '{:03d} {:03d}'.format(1, 2)değerleri sırayla sırayla atar.
Ejderha

1
@ JasonR.Coombs: Python 3'te printne zaman bir printfonksiyon olmalı ? Ben ebeveynlerde kurguladım; sadece bir şey basıldığından, şimdi Py2 ve Py3 üzerinde aynı şekilde çalışır.
ShadowRanger


353

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'

123

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 .


3
PEP 3101,% 'nin herhangi bir şekilde kullanımdan kaldırıldığını belirtmez.
zwirbeltier

@zwirbeltier PEP 3101 formatın nasıl kullanılacağını açıklıyor, demek istediğim bu.
Konrad Rudolph

4
"DÜZENLE" ifadesi hala "… bu biçimlendirme yönteminin kullanımdan kaldırıldığı…".
14:38, zwirbeltier

1
@zwirbeltier Evet, kullanımdan kaldırıldı. Ancak bu doğrudan KEP'de belirtilmemiştir. Bununla birlikte, belgeler formatbunun yerine kullanıldığını söylüyor ve insanlar bunu genellikle itiraz etme niyeti olarak yorumluyorlar.
Konrad Rudolph

1
@LarsH Bunu bulduğunuz için teşekkür ederiz. Yani programın oldukça gerisindeler (Python 3.1 gelecekte değil, uzak geçmişte). Bu göz önüne alındığında, hala Python geliştirme programı yeni, keyfi bir yönde her değiştiğinde cevabın yanıltıcı olduğunu düşünmüyorum. Her neyse, bu bana cevabımdan bazı alakasız ve güncel olmayan şeyleri kaldırma fırsatı verdi.
Konrad Rudolph

63

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'

56
>>> '99'.zfill(5)
'00099'
>>> '99'.rjust(5,'0')
'00099'

tam tersini istiyorsanız:

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

39

str(n).zfill(width)birlikte çalışacaktır strings, int, s floatler ... ve Python 2. x ve 3. x uyumlu:

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

23

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


23

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.

Verim

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

uygulama

Biraz kazma ile, zfillyö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 padfonksiyonu da adlandırılır ljust, rjustve centerhem 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, zfillorijinal 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'

performans için, python2 vs python3 kullanım senaryoları dahil olmak üzere f dizelerinin daha iyi olduğu durumlar var mı? Ayrıca, ben zfill bir dokümanlara bağlantısı olduğu cevabını yardımcı olacağını yaygın olmadığı için düşünmek
elad gümüş

@eladsilver, senin niyet bağlıdır ile akılda davranışı tutarak +ve -ve ben dokümanlar için bir bağlantı eklendi!
Aaron Hall

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


1980'den beri ... 60 yaşında bir programcı mısın ... "%0*d" % (width, x)python tarafından nasıl yorumlandığına dair daha fazla açıklama yapabilir misiniz ?
Lee

15

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'

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

Yeni sözdizimi örneği için teşekkürler. char 'x' doldurur: v = "A18"; s = f '{v: x> 8}' + "|"; veya s = v.ljust (8, "x") + "|";
Charlie 木匠

@Charlie that Bu bana bir soru muydu yoksa sadece bir açıklama mıydı?
ruohola

sadece bir ifade. biraz daha kullanım test etti.
Charlie

4

Tamsayı olarak kaydedilen posta kodları için:

>>> a = 6340
>>> b = 90210
>>> print '%05d' % a
06340
>>> print '%05d' % b
90210

1
Haklısın ve zfill ile öneriyi her nasılsa daha iyi

3

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


1

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

0

Tamam da:

 h = 2
 m = 7
 s = 3
 print("%02d:%02d:%02d" % (h, m, s))

yani çıktı: "02:07:03"


-2

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

1
Bu sadece pozitif sayılar için geçerlidir. Negatifleri de istiyorsanız biraz daha karmaşık hale gelir. Ancak bu ifade, bu tür şeylere aldırmazsanız, hızlı ve kirli işler için iyidir.
J Lacar

Bunun neden reddedildiğine dair hiçbir fikrim yok. Nedeni negatif sayılar üzerinde yeterince adil çalışmıyorsa, ancak sıfırlarla ped bırakmanın ezici nedeni kimlik numaraları içindir. Negatif kimlik numaralarınız varsa daha büyük sorunlarınız olduğunu düşünüyorum ... pedinizin '00000-1234' formunda olmasını mı bekliyorsunuz? veya '-000001234'? Dürüst olmak gerekirse, bu cevabın işe yaradığı sorusu göz önüne alındığında, basit, temiz, genişletilebilir. Zfill olmayabilir ama soruyu cevaplarsa kaldırılmalıdır.
TastySlowCooker
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.