it-swarm.com.de

Schönste Weg, um Nullen zu einer Zeichenfolge aufzufüllen

Was ist die pythonischste Methode, um eine numerische Zeichenfolge mit Nullen nach links aufzufüllen, d. H. Die numerische Zeichenfolge hat eine bestimmte Länge?

1234
Faisal

Streicher:

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

Und für Zahlen:

>>> n = 4
>>> print('%03d' % n)
004
>>> print(format(n, '03')) # python >= 2.6
004
>>> print('{0:03d}'.format(n))  # python >= 2.6
004
>>> print('{foo:03d}'.format(foo=n))  # python >= 2.6
004
>>> print('{:03d}'.format(n))  # python >= 2.7 + python3
004
>>> print('{0:03d}'.format(n))  # python 3
004
>>> print(f'{n:03}') # python >= 3.6
004

Dokumentation zur String-Formatierung .

2034
Harley Holcombe

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

In diesem Beispiel wird eine Zeichenfolge mit 10 Zeichen erstellt, die nach Bedarf aufgefüllt wird.

>>> t = 'test'
>>> t.rjust(10, '0')
>>> '000000test'
317
Paul D. Eden

Neben zfill können Sie auch 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 für Zeichenkettenformatierung und f-Zeichenketten .

100
Konrad Rudolph
>>> '99'.zfill(5)
'00099'
>>> '99'.rjust(5,'0')
'00099'

wenn Sie das Gegenteil wollen:

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

Dies funktioniert sowohl in Python 2 als auch in Python 3:

>>> "{:0>2}".format("1")  # Works for both numbers and strings.
'01'
>>> "{:02}".format(1)  # Works only for numbers.
'01'

Zur Verwendung mit 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'
47
Cees Timmerman

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'
36
Johnsyweb
width = 10
x = 5
print "%0*d" % (width, x)
> 0000000005

In der gedruckten Dokumentation finden Sie alle interessanten Details!

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

Diese letzte Zeile sollte jetzt lauten:

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

Das heißt print() ist jetzt eine Funktion, keine Anweisung. Beachte, dass ich den Old School printf() -Stil immer noch bevorzuge, weil er meiner Meinung nach besser liest und weil ich diese Schreibweise seit Januar 1980 verwende. Etwas ... alte Hunde ... etwas etwas. .. neue Tricks.

17
Peter Rowell

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

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 Füllzeichen "2" ersetzt werden sollen. Die Standardeinstellung ist ein leeres Leerzeichen

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

":" symbolisiert die format_spec

17
elad silver

Was ist die pythonischste Methode, um eine numerische Zeichenfolge mit Nullen nach links aufzufüllen, d. H. Die numerische Zeichenfolge hat eine bestimmte Länge?

str.zfill ist speziell dafür vorgesehen:

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

Beachten Sie, dass es speziell dafür vorgesehen ist, numerische Zeichenfolgen wie gewünscht zu behandeln und einen _+_ 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 ansonsten vorberechnet:

_>>> 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 zfill -Methode 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.

Zunächst wird das Argument positionsbezogen analysiert, dh es sind keine Schlüsselwortargumente zulässig:

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

zfill ruft pad auf (diese pad Funktion wird auch von ljust, rjust und center aufgerufen). Dies kopiert im Grunde den Inhalt in eine neue Zeichenfolge und füllt die Auffüllung.

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

Nachdem pad aufgerufen wurde, verschiebt zfill alle ursprünglich vorhergehenden _+_ oder _-_ an den Anfang der Zeichenfolge.

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

_>>> '+foo'.zfill(10)
'+000000foo'
>>> '-foo'.zfill(10)
'-000000foo'
_
15
Aaron Hall

Für Postleitzahlen, die als Ganzzahlen gespeichert sind:

>>> a = 6340
>>> b = 90210
>>> print '%05d' % a
06340
>>> print '%05d' % b
90210
4
user221014
>>> width = 4
>>> x = 5
>>> print("%0*d" %(width,x))
>>> 00005

dies funktioniert in python 3.x

4
Saad

Bei Verwendung von >= Python 3.6 ist die Verwendung von f-Zeichenfolgen mit Zeichenfolgenformatierung die sauberste Methode:

>>> s = f"{1:08}"  # inline
>>> s
'00000001'
>>> n = 1
>>> s = f"{n:08}"  # int variable
>>> s
'00000001'
>>> c = "1"
>>> s = f"{c:0>8}"  # str variable
>>> s
'00000001'
2
ruohola

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 sehr groß, aber in allen Tests war die zfill -Lösung die schnellste.

2

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