Подтвердить что ты не робот

Самый хороший способ дополнить нули до строки

Какой самый Pythonic способ дополнить числовую строку нулями слева, то есть, чтобы числовая строка имела определенную длину?

4b9b3361

Ответ 1

Строки:

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

А для номеров:

>>> n = 4
>>> 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
>>> print(f'{n:03}') # python >= 3.6
004

Документация по форматированию строк.

Ответ 2

Просто используйте rjust метод строкового объекта.

В этом примере строка длиной 10 символов будет заполняться, если необходимо.

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

Ответ 3

Помимо zfill, вы можете использовать общее форматирование строки:

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

Документация по форматированию строк и f-строк.

Ответ 4

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

если вы хотите обратное:

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

Ответ 5

Это работает как в Python 2, так и в Python 3:

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

Для использования с Python 3. 6+ с использованием f-строк:

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

Ответ 6

str(n).zfill(width) будет работать с string s, int s, float s... и совместим с Python 2.x и 3.x:

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

Ответ 7

Для тех, кто пришел сюда, чтобы понять, а не просто быстрый ответ. Я делаю это специально для временных строк:

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", по умолчанию это пустое пространство

" > " символы присваивают все символы 2 "0" слева от строки

":" символы format_spec

Ответ 8

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

См. документацию по печати для всех интересных деталей!

Обновление для Python 3.x(спустя 7,5 лет)

Последняя строка должна быть следующей:

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

т.е. print() теперь является функцией, а не оператором. Заметьте, что я по-прежнему предпочитаю стиль Old School printf(), потому что IMNSHO, он читает лучше, и потому, что, гм, я использовал эту запись с января 1980 года. Что-то... старые собаки.. что-то... новые трюки.

Ответ 9

Какой самый питонный способ дополнить числовую строку нулями слева, то есть, чтобы числовая строка имела определенную длину?

str.zfill специально предназначен для этого:

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

Обратите внимание, что он специально предназначен для обработки числовых строк по запросу и перемещает + или - в начало строки:

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

Вот помощь по 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.

Спектакль

Это также самый эффективный из альтернативных методов:

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

Чтобы лучше сравнить яблоки с яблоками для метода % (обратите внимание, что он на самом деле медленнее), который в противном случае будет предварительно вычислять:

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

Реализация

Немного покопавшись, я нашел реализацию метода zfill в 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;
}

Давайте пройдемся по этому C-коду.

Сначала он анализирует аргумент позиционно, то есть он не допускает аргументы с ключевыми словами:

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

Затем он проверяет, имеет ли он ту же длину или больше, и в этом случае он возвращает строку.

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

zfill вызывает pad (эта функция pad также ljust, rjust и center). Это в основном копирует содержимое в новую строку и заполняет отступы.

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

После вызова pad, zfill перемещает любой изначально предшествующий + или - в начало строки.

Обратите внимание, что для того, чтобы исходная строка была фактически числовой, не требуется:

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

Ответ 10

Для почтовых индексов, сохраненных как целые числа:

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

Ответ 11

>>> width = 4
>>> x = 5
>>> print("%0*d" %(width,x))
>>> 00005

это будет работать в python 3.x

Ответ 12

При использовании Python >= 3.6 самый чистый способ - использовать f-строки с форматированием строки:

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

Ответ 13

Сравнение быстрого времени:

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]

Я делал разные тесты разных повторений. Различия невелики, но во всех тестах решение zfill было самым быстрым.

Ответ 14

Другой подход заключается в использовании списочного понимания с проверкой условий на длину. Ниже приведена демонстрация:

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

Ответ 15

Вы также можете повторить "0", добавьте его к str(n) и получите самый правый срез ширины. Быстрое и грязное выражение.

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