Wie fülle ich einen String mit Nullen auf?


1445

Was ist eine pythonische Methode, um eine numerische Zeichenfolge mit Nullen links aufzufüllen, dh die numerische Zeichenfolge hat eine bestimmte Länge?

Antworten:


2393

Saiten:

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

Und für Zahlen:

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

Dokumentation zur Zeichenfolgenformatierung .


3
Unbekannter Formatcode 'd' für Objekt vom Typ 'float'.
Cees Timmerman

7
Kommentare python >= 2.6sind falsch. Diese Syntax funktioniert nicht python >= 3. Sie könnten es in ändern python < 3, aber kann ich vorschlagen, stattdessen immer Klammern zu verwenden und die Kommentare ganz wegzulassen (was die empfohlene Verwendung fördert)?
Jason R. Coombs

4
Beachten Sie, dass Sie Ihre Formatzeichenfolgen nicht nummerieren müssen: '{:03d} {:03d}'.format(1, 2)Ordnet die Werte implizit der Reihe nach zu.
Dragon

1
@ JasonR.Coombs: Ich nehme an, Sie meinten die printAussage, wann es eine printFunktion auf Python 3 sein sollte? Ich habe in den Parens bearbeitet; Da nur eines gedruckt wird, funktioniert es jetzt auf Py2 und Py3 identisch.
ShadowRanger


353

Verwenden Sie einfach die rjust- Methode des String-Objekts.

In diesem Beispiel wird eine Zeichenfolge mit 10 Zeichen erstellt und bei Bedarf aufgefüllt.

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

123

Außerdem zfillkönnen Sie die allgemeine Formatierung von Zeichenfolgen verwenden:

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

Dokumentation zur Formatierung von Zeichenfolgen und F-Zeichenfolgen .


3
PEP 3101 gibt nicht an, dass% in irgendeiner Weise veraltet ist.
zwirbeltier

@zwirbeltier PEP 3101 erklärt, wie man das Format verwendet, meinte ich.
Konrad Rudolph

4
In "BEARBEITEN" heißt es weiterhin "... diese Formatierungsmethode ist veraltet ...".
zwirbeltier

1
@zwirbeltier Ja, und es ist veraltet. Dies ist jedoch nicht direkt im PEP angegeben. In der Dokumentation heißt es jedoch, formatstattdessen zu verwenden , und die Leute interpretieren dies im Allgemeinen als Absicht, sie zu verwerfen.
Konrad Rudolph

1
@LarsH Danke, dass du das gefunden hast. Sie liegen also stark hinter dem Zeitplan zurück (Python 3.1 liegt nicht in der Zukunft, sondern in der fernen Vergangenheit). Angesichts dessen glaube ich immer noch nicht, dass die Antwort irreführend war, sondern nicht jedes Mal streng aktualisiert wurde, wenn sich der Python-Entwicklungsplan in eine neue, willkürliche Richtung änderte. Auf jeden Fall gab mir dies die Möglichkeit, irrelevante und veraltete Dinge aus meiner Antwort zu entfernen.
Konrad Rudolph

63

Für Python 3.6+ mit F-Strings:

>>> i = 1
>>> f"{i:0>2}"  # Works for both numbers and strings.
'01'
>>> f"{i:02}"  # Works only for numbers.
'01'

Für Python 2 bis Python 3.5:

>>> "{: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'

wenn Sie das Gegenteil wollen:

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

39

str(n).zfill(width)funktioniert mit strings, ints, floats ... und ist Python 2. x und 3. x kompatibel:

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

23

Für diejenigen, die hierher gekommen sind, um zu verstehen und nicht nur eine schnelle Antwort. Ich mache diese speziell für Zeitzeichenfolgen:

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" -Symbole, die durch die "2" -Zeichenzeichen ersetzt werden sollen. Die Standardeinstellung ist ein leeres Leerzeichen

">" Symbole weisen alle 2 "0" Zeichen links von der Zeichenfolge zu

":" symbolisiert die format_spec


23

Was ist die pythonischste Methode, um eine numerische Zeichenfolge mit Nullen links aufzufüllen, dh, die numerische Zeichenfolge hat eine bestimmte Länge?

str.zfill ist speziell dazu gedacht:

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

Beachten Sie, dass es speziell dafür vorgesehen ist, numerische Zeichenfolgen wie angefordert zu behandeln und ein +oder -an den Anfang der Zeichenfolge zu verschieben:

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

Hier ist die Hilfe zu 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.

Performance

Dies ist auch die leistungsstärkste alternative Methode:

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

Um Äpfel am besten mit Äpfeln für die %Methode zu vergleichen (beachten Sie, dass sie tatsächlich langsamer ist), die sonst vorberechnet wird:

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

Implementierung

Mit ein wenig Graben fand ich die Implementierung der zfillMethode in 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;
}

Lassen Sie uns diesen C-Code durchgehen.

Zuerst wird das Argument positionell analysiert, was bedeutet, dass keine Schlüsselwortargumente zulässig sind:

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

Anschließend wird geprüft, ob die Länge gleich oder länger ist. In diesem Fall wird die Zeichenfolge zurückgegeben.

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

zfillAnrufe pad(diese padFunktion auch durch genannt wird ljust, rjustund centerals auch). Dies kopiert im Grunde den Inhalt in eine neue Zeichenfolge und füllt die Polsterung aus.

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;
}

Nach dem Aufruf pad, zfillbewegt sich ein ursprünglich vorhergehenden +oder -zum Anfang des Strings.

Beachten Sie, dass die ursprüngliche Zeichenfolge nicht numerisch sein muss:

>>> '+foo'.zfill(10)
'+000000foo'
>>> '-foo'.zfill(10)
'-000000foo'

Gibt es für die Leistung Fälle, in denen f-Strings besser sind, einschließlich Anwendungsfällen für Python2 oder Python3? Ich denke auch, da zfill nicht üblich ist, würde es Ihrer Antwort helfen, einen Link zu den Dokumenten zu haben
elad silver

@eladsilver hängt von Ihrer Absicht ab, wobei Sie das Verhalten mit +und berücksichtigen -, und ich habe einen Link zu den Dokumenten hinzugefügt!
Aaron Hall

17
width = 10
x = 5
print "%0*d" % (width, x)
> 0000000005

In der Druckdokumentation finden Sie alle aufregenden Details!

Update für Python 3.x (7,5 Jahre später)

Diese letzte Zeile sollte jetzt sein:

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

Dh print()ist jetzt eine Funktion, keine Aussage. Beachten Sie, dass ich den Old-School- printf()Stil immer noch bevorzuge, weil er, IMNSHO, besser liest und weil ich diese Notation seit Januar 1980 verwende. Etwas ... alte Hunde ... etwas etwas ... neue Tricks.


seit 1980 ... also bist du ein 60 Jahre alter Programmierer ... könntest du bitte mehr erklären, wie "%0*d" % (width, x)Python interpretiert wird?
Lee

15

Bei Verwendung von Python >= 3.6ist es am saubersten, F-Strings mit String-Formatierung zu verwenden :

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

Ich würde es vorziehen, mit einem zu formatieren int, da nur dann das Zeichen richtig behandelt wird:

>>> f"{-1:08}"
'-0000001'

>>> f"{1:+08}"
'+0000001'

>>> f"{'-1':0>8}"
'000000-1'

Vielen Dank für das neue Syntaxbeispiel. Füllzeichen 'x' ist: v = "A18"; s = f '{v: x> 8}' + "|"; oder s = v.ljust (8, "x") + "|";
Charlie, 21.

@Charlie 木匠 War das eine Frage an mich oder nur eine Aussage?
Ruohola

nur eine Aussage. etwas mehr Verwendung getestet.
Charlie 23

4

Für als Ganzzahlen gespeicherte Postleitzahlen:

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

1
Sie haben Recht, und ich mag Ihren Vorschlag mit zfill sowieso besser

3

Schneller Timing-Vergleich:

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]

Ich habe verschiedene Tests mit verschiedenen Wiederholungen durchgeführt. Die Unterschiede sind nicht groß, aber in allen Tests war die zfillLösung am schnellsten.


1

Ein anderer Ansatz wäre die Verwendung eines Listenverständnisses mit einer Bedingungsprüfung auf Längen. Unten ist eine Demonstration:

# 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

Es ist auch in Ordnung:

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

Die Ausgabe lautet also: "02:07:03"


-2

Sie können auch "0" wiederholen, vorstellen str(n)und die am weitesten rechts liegende Scheibe erhalten. Schneller und schmutziger kleiner Ausdruck.

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

1
Dies funktioniert jedoch nur für positive Zahlen. Es wird etwas komplizierter, wenn Sie auch Negative wollen. Aber dieser Ausdruck ist gut für schnelle und schmutzige Arbeit, wenn Ihnen so etwas nichts ausmacht.
J Lacar

Ich habe absolut keine Ahnung, warum dies abgelehnt wird. Wenn es daran liegt, dass es bei negativen Zahlen nicht fair genug funktioniert, aber der überwältigende Grund, warum man das Feld mit Nullen belassen würde, sind ID-Zahlen. Wenn Sie negative ID-Nummern haben, haben Sie wahrscheinlich größere Probleme. Erwarten Sie, dass Ihr Pad die Form '00000-1234' hat? oder '-000001234'? Ehrlich gesagt, angesichts der Frage, dass diese Antwort funktioniert, ist sie einfach, sauber und erweiterbar. Es ist möglicherweise nicht zfill, aber wenn es die Frage beantwortet, sollte es positiv bewertet werden.
TastySlowCooker
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.