How to implement string.center() by padding the extra character always on the left?

Viewed 37

The builtin center() padding the extra character either on left or on the right depending on the string's length, e.g. 'bar'.center(10, '-') is ---bar----, the extra - is on the right but hi.center(9,'-') is ----hi---, the extra is on the left.

But in my case I need the extra padding(if any) always on the left. What is the simple way to do that, as there are many ways to do that ?

And why does builtin center() implement in this way? Actually I am more curious in this.

2 Answers

You can implement your own version that left-pads the string. It's pretty simple, you make sure center creates an even-sized string, then if there is a reminder left you pad it on the left

In [1]: def left_center(word, sep, length):
   ...:     reminder = (length - len(word)) % 2
   ...:     return f'{reminder*sep}{word.center(length-reminder, sep)}'
   ...:

In [2]: left_center('bar', '-', 10)
Out[2]: '----bar---'

In [3]: left_center('hi', '-', 9)
Out[3]: '----hi---'

for left_center('bar', '-', 10) it does this:

reminder = (10 - 3) % 2 # which is equal to 1
f'{1*"-"}{"bar".center(9, "-")} # '----bar---'

The original implementation of str.center was added here, in 1990:

# Center a string
def center(s, width):
    n = len(s)
    if n >= width: return s
    return ' '*((width-n)/2) +  s + ' '*(width -(width-n)/2)

It was changed a year later, in 1991, to

# Center a string
def center(s, width):
    """center(s, width) -> string
    Return a center version of s, in a field of the specified
    width. padded with spaces as needed.  The string is never
    truncated.
    """
    n = width - len(s)
    if n <= 0: return s
    half = n/2
    if n%2 and width%2:
        # This ensures that center(center(s, i), j) = center(s, j)
        half = half+1
    return ' '*half +  s + ' '*(n-half)

and the current C implementation found here does

static PyObject *
stringlib_center_impl(PyObject *self, Py_ssize_t width, char fillchar)
/*[clinic end generated code: output=d8da2e055288b4c2 input=3776fd278765d89b]*/
{
    Py_ssize_t marg, left;

    if (STRINGLIB_LEN(self) >= width) {
        return return_self(self);
    }

    marg = width - STRINGLIB_LEN(self);
    left = marg / 2 + (marg & width & 1);

    return pad(self, left, marg - left, fillchar);
}

I suspect the "why" for the current implementation is the

This ensures that center(center(s, i), j) = center(s, j)

comment, but you'd have to ask Guido for confirmation.

Related