Was ist eine pythonische Methode, um eine numerische Zeichenfolge mit Nullen links aufzufüllen, dh die numerische Zeichenfolge hat eine bestimmte Länge?
Was ist eine pythonische Methode, um eine numerische Zeichenfolge mit Nullen links aufzufüllen, dh die numerische Zeichenfolge hat eine bestimmte Länge?
Antworten:
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
python >= 2.6
sind 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)?
'{:03d} {:03d}'.format(1, 2)
Ordnet die Werte implizit der Reihe nach zu.
print
Aussage, wann es eine print
Funktion auf Python 3 sein sollte? Ich habe in den Parens bearbeitet; Da nur eines gedruckt wird, funktioniert es jetzt auf Py2 und Py3 identisch.
Außerdem zfill
kö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 .
format
stattdessen zu verwenden , und die Leute interpretieren dies im Allgemeinen als Absicht, sie zu verwerfen.
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'
>>> '99'.zfill(5)
'00099'
>>> '99'.rjust(5,'0')
'00099'
wenn Sie das Gegenteil wollen:
>>> '99'.ljust(5,'0')
'99000'
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
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.
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
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.
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'
zfill
Anrufe pad
(diese pad
Funktion auch durch genannt wird ljust
, rjust
und center
als 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
, zfill
bewegt 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'
+
und berücksichtigen -
, und ich habe einen Link zu den Dokumenten hinzugefügt!
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.
"%0*d" % (width, x)
Python interpretiert wird?
Bei Verwendung von Python >= 3.6
ist 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'
Für als Ganzzahlen gespeicherte Postleitzahlen:
>>> a = 6340
>>> b = 90210
>>> print '%05d' % a
06340
>>> print '%05d' % b
90210
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 zfill
Lösung am schnellsten.
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']
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:]