From 4f8f9765766a126ebfff3c81655454821f1ad532 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Wed, 26 Nov 2003 08:21:35 +0000 Subject: Add optional fillchar argument to ljust(), rjust(), and center() string methods. --- Doc/lib/libstdtypes.tex | 14 +++++++----- Lib/UserString.py | 9 +++++--- Lib/string.py | 24 ++++++++++---------- Lib/test/string_tests.py | 6 ++--- Misc/NEWS | 4 ++++ Objects/stringobject.c | 31 +++++++++++++++----------- Objects/unicodeobject.c | 58 +++++++++++++++++++++++++++++++++++++----------- 7 files changed, 96 insertions(+), 50 deletions(-) diff --git a/Doc/lib/libstdtypes.tex b/Doc/lib/libstdtypes.tex index 4eb4595..9281dac 100644 --- a/Doc/lib/libstdtypes.tex +++ b/Doc/lib/libstdtypes.tex @@ -546,9 +546,9 @@ objects support: Return a copy of the string with only its first character capitalized. \end{methoddesc} -\begin{methoddesc}[string]{center}{width} +\begin{methoddesc}[string]{center}{width\optional{, fillchar}} Return centered in a string of length \var{width}. Padding is done -using spaces. +using the specified \var{fillchar} (default is a space). \end{methoddesc} \begin{methoddesc}[string]{count}{sub\optional{, start\optional{, end}}} @@ -645,9 +645,10 @@ sequence \var{seq}. The separator between elements is the string providing this method. \end{methoddesc} -\begin{methoddesc}[string]{ljust}{width} +\begin{methoddesc}[string]{ljust}{width\optional{, fillchar}} Return the string left justified in a string of length \var{width}. -Padding is done using spaces. The original string is returned if +Padding is done using the specified \var{fillchar} (default is a +space). The original string is returned if \var{width} is less than \code{len(\var{s})}. \end{methoddesc} @@ -683,9 +684,10 @@ Like \method{rfind()} but raises \exception{ValueError} when the substring \var{sub} is not found. \end{methoddesc} -\begin{methoddesc}[string]{rjust}{width} +\begin{methoddesc}[string]{rjust}{width\optional{, fillchar}} Return the string right justified in a string of length \var{width}. -Padding is done using spaces. The original string is returned if +Padding is done using the specified \var{fillchar} (default is a space). +The original string is returned if \var{width} is less than \code{len(\var{s})}. \end{methoddesc} diff --git a/Lib/UserString.py b/Lib/UserString.py index 730cdba..f28e54c 100755 --- a/Lib/UserString.py +++ b/Lib/UserString.py @@ -60,7 +60,8 @@ class UserString: # the following methods are defined in alphabetical order: def capitalize(self): return self.__class__(self.data.capitalize()) - def center(self, width): return self.__class__(self.data.center(width)) + def center(self, width, *args): + return self.__class__(self.data.center(width, *args)) def count(self, sub, start=0, end=sys.maxint): return self.data.count(sub, start, end) def decode(self, encoding=None, errors=None): # XXX improve this? @@ -97,7 +98,8 @@ class UserString: def istitle(self): return self.data.istitle() def isupper(self): return self.data.isupper() def join(self, seq): return self.data.join(seq) - def ljust(self, width): return self.__class__(self.data.ljust(width)) + def ljust(self, width, *args): + return self.__class__(self.data.ljust(width, *args)) def lower(self): return self.__class__(self.data.lower()) def lstrip(self, chars=None): return self.__class__(self.data.lstrip(chars)) def replace(self, old, new, maxsplit=-1): @@ -106,7 +108,8 @@ class UserString: return self.data.rfind(sub, start, end) def rindex(self, sub, start=0, end=sys.maxint): return self.data.rindex(sub, start, end) - def rjust(self, width): return self.__class__(self.data.rjust(width)) + def rjust(self, width, *args): + return self.__class__(self.data.rjust(width, *args)) def rstrip(self, chars=None): return self.__class__(self.data.rstrip(chars)) def split(self, sep=None, maxsplit=-1): return self.data.split(sep, maxsplit) diff --git a/Lib/string.py b/Lib/string.py index 5b5ddc3..0a77f46 100644 --- a/Lib/string.py +++ b/Lib/string.py @@ -237,37 +237,37 @@ def atol(s, base=10): # Left-justify a string -def ljust(s, width): - """ljust(s, width) -> string +def ljust(s, width, *args): + """ljust(s, width[, fillchar]) -> string Return a left-justified version of s, in a field of the specified width, padded with spaces as needed. The string is - never truncated. + never truncated. If specified the fillchar is used instead of spaces. """ - return s.ljust(width) + return s.ljust(width, *args) # Right-justify a string -def rjust(s, width): - """rjust(s, width) -> string +def rjust(s, width, *args): + """rjust(s, width[, fillchar]) -> string Return a right-justified version of s, in a field of the specified width, padded with spaces as needed. The string is - never truncated. + never truncated. If specified the fillchar is used instead of spaces. """ - return s.rjust(width) + return s.rjust(width, *args) # Center a string -def center(s, width): - """center(s, width) -> string +def center(s, width, *args): + """center(s, width[, fillchar]) -> string Return a center version of s, in a field of the specified width. padded with spaces as needed. The string is never - truncated. + truncated. If specified the fillchar is used instead of spaces. """ - return s.center(width) + return s.center(width, *args) # Zero-fill a number, e.g., (12, 3) --> '012' and (-3, 3) --> '-03' # Decadent feature: the argument may be a string or a number diff --git a/Lib/test/string_tests.py b/Lib/test/string_tests.py index af171d0..236c577 100644 --- a/Lib/test/string_tests.py +++ b/Lib/test/string_tests.py @@ -227,7 +227,7 @@ class CommonTest(unittest.TestCase): self.checkequal('abc ', 'abc', 'ljust', 6) self.checkequal('abc', 'abc', 'ljust', 3) self.checkequal('abc', 'abc', 'ljust', 2) - + self.checkequal('abc*******', 'abc', 'ljust', 10, '*') self.checkraises(TypeError, 'abc', 'ljust') def test_rjust(self): @@ -235,7 +235,7 @@ class CommonTest(unittest.TestCase): self.checkequal(' abc', 'abc', 'rjust', 6) self.checkequal('abc', 'abc', 'rjust', 3) self.checkequal('abc', 'abc', 'rjust', 2) - + self.checkequal('*******abc', 'abc', 'rjust', 10, '*') self.checkraises(TypeError, 'abc', 'rjust') def test_center(self): @@ -243,7 +243,7 @@ class CommonTest(unittest.TestCase): self.checkequal(' abc ', 'abc', 'center', 6) self.checkequal('abc', 'abc', 'center', 3) self.checkequal('abc', 'abc', 'center', 2) - + self.checkequal('***abc****', 'abc', 'center', 10, '*') self.checkraises(TypeError, 'abc', 'center') def test_swapcase(self): diff --git a/Misc/NEWS b/Misc/NEWS index a3f3a18..c9b7baa 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,10 @@ What's New in Python 2.4 alpha 1? Core and builtins ----------------- +- For str and unicode objects, the ljust(), center(), and rjust() + methods now accept an optional argument specifying a fill + character other than a space. + - When method objects have an attribute that can be satisfied either by the function object or by the method object, the function object's attribute usually wins. Christian Tismer pointed out that diff --git a/Objects/stringobject.c b/Objects/stringobject.c index 0a22440..739cc3e 100644 --- a/Objects/stringobject.c +++ b/Objects/stringobject.c @@ -2617,16 +2617,18 @@ pad(PyStringObject *self, int left, int right, char fill) } PyDoc_STRVAR(ljust__doc__, -"S.ljust(width) -> string\n" +"S.ljust(width[, fillchar]) -> string\n" "\n" "Return S left justified in a string of length width. Padding is\n" -"done using spaces."); +"done using the specified fill character (default is a space)."); static PyObject * string_ljust(PyStringObject *self, PyObject *args) { int width; - if (!PyArg_ParseTuple(args, "i:ljust", &width)) + char fillchar = ' '; + + if (!PyArg_ParseTuple(args, "i|c:ljust", &width, &fillchar)) return NULL; if (PyString_GET_SIZE(self) >= width && PyString_CheckExact(self)) { @@ -2634,21 +2636,23 @@ string_ljust(PyStringObject *self, PyObject *args) return (PyObject*) self; } - return pad(self, 0, width - PyString_GET_SIZE(self), ' '); + return pad(self, 0, width - PyString_GET_SIZE(self), fillchar); } PyDoc_STRVAR(rjust__doc__, -"S.rjust(width) -> string\n" +"S.rjust(width[, fillchar]) -> string\n" "\n" "Return S right justified in a string of length width. Padding is\n" -"done using spaces."); +"done using the specified fill character (default is a space)"); static PyObject * string_rjust(PyStringObject *self, PyObject *args) { int width; - if (!PyArg_ParseTuple(args, "i:rjust", &width)) + char fillchar = ' '; + + if (!PyArg_ParseTuple(args, "i|c:rjust", &width, &fillchar)) return NULL; if (PyString_GET_SIZE(self) >= width && PyString_CheckExact(self)) { @@ -2656,23 +2660,24 @@ string_rjust(PyStringObject *self, PyObject *args) return (PyObject*) self; } - return pad(self, width - PyString_GET_SIZE(self), 0, ' '); + return pad(self, width - PyString_GET_SIZE(self), 0, fillchar); } PyDoc_STRVAR(center__doc__, -"S.center(width) -> string\n" +"S.center(width[, fillchar]) -> string\n" "\n" -"Return S centered in a string of length width. Padding is done\n" -"using spaces."); +"Return S centered in a string of length width. Padding is\n" +"done using the specified fill character (default is a space)"); static PyObject * string_center(PyStringObject *self, PyObject *args) { int marg, left; int width; + char fillchar = ' '; - if (!PyArg_ParseTuple(args, "i:center", &width)) + if (!PyArg_ParseTuple(args, "i|c:center", &width, &fillchar)) return NULL; if (PyString_GET_SIZE(self) >= width && PyString_CheckExact(self)) { @@ -2683,7 +2688,7 @@ string_center(PyStringObject *self, PyObject *args) marg = width - PyString_GET_SIZE(self); left = marg / 2 + (marg & width & 1); - return pad(self, left, marg - left, ' '); + return pad(self, left, marg - left, fillchar); } PyDoc_STRVAR(zfill__doc__, diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index e4fe531..c950f8b 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -4404,19 +4404,47 @@ onError: } #endif +/* Argument converter. Coerces to a single unicode character */ + +static int +convert_uc(PyObject *obj, void *addr) +{ + Py_UNICODE *fillcharloc = (Py_UNICODE *)addr; + PyObject *uniobj; + Py_UNICODE *unistr; + + uniobj = PyUnicode_FromObject(obj); + if (uniobj == NULL) { + PyErr_SetString(PyExc_TypeError, + "The fill character cannot be converted to Unicode"); + return 0; + } + if (PyUnicode_GET_SIZE(uniobj) != 1) { + PyErr_SetString(PyExc_TypeError, + "The fill character must be exactly one character long"); + Py_DECREF(uniobj); + return 0; + } + unistr = PyUnicode_AS_UNICODE(uniobj); + *fillcharloc = unistr[0]; + Py_DECREF(uniobj); + return 1; +} + PyDoc_STRVAR(center__doc__, -"S.center(width) -> unicode\n\ +"S.center(width[, fillchar]) -> unicode\n\ \n\ -Return S centered in a Unicode string of length width. Padding is done\n\ -using spaces."); +Return S centered in a Unicode string of length width. Padding is\n\ +done using the specified fill character (default is a space)"); static PyObject * unicode_center(PyUnicodeObject *self, PyObject *args) { int marg, left; int width; + Py_UNICODE fillchar = ' '; - if (!PyArg_ParseTuple(args, "i:center", &width)) + if (!PyArg_ParseTuple(args, "i|O&:center", &width, convert_uc, &fillchar)) return NULL; if (self->length >= width && PyUnicode_CheckExact(self)) { @@ -4427,7 +4455,7 @@ unicode_center(PyUnicodeObject *self, PyObject *args) marg = width - self->length; left = marg / 2 + (marg & width & 1); - return (PyObject*) pad(self, left, marg - left, ' '); + return (PyObject*) pad(self, left, marg - left, fillchar); } #if 0 @@ -5170,16 +5198,18 @@ unicode_length(PyUnicodeObject *self) } PyDoc_STRVAR(ljust__doc__, -"S.ljust(width) -> unicode\n\ +"S.ljust(width[, fillchar]) -> unicode\n\ \n\ Return S left justified in a Unicode string of length width. Padding is\n\ -done using spaces."); +done using the specified fill character (default is a space)."); static PyObject * unicode_ljust(PyUnicodeObject *self, PyObject *args) { int width; - if (!PyArg_ParseTuple(args, "i:ljust", &width)) + Py_UNICODE fillchar = ' '; + + if (!PyArg_ParseTuple(args, "i|O&:ljust", &width, convert_uc, &fillchar)) return NULL; if (self->length >= width && PyUnicode_CheckExact(self)) { @@ -5187,7 +5217,7 @@ unicode_ljust(PyUnicodeObject *self, PyObject *args) return (PyObject*) self; } - return (PyObject*) pad(self, 0, width - self->length, ' '); + return (PyObject*) pad(self, 0, width - self->length, fillchar); } PyDoc_STRVAR(lower__doc__, @@ -5552,16 +5582,18 @@ unicode_rindex(PyUnicodeObject *self, PyObject *args) } PyDoc_STRVAR(rjust__doc__, -"S.rjust(width) -> unicode\n\ +"S.rjust(width[, fillchar]) -> unicode\n\ \n\ Return S right justified in a Unicode string of length width. Padding is\n\ -done using spaces."); +done using the specified fill character (default is a space)."); static PyObject * unicode_rjust(PyUnicodeObject *self, PyObject *args) { int width; - if (!PyArg_ParseTuple(args, "i:rjust", &width)) + Py_UNICODE fillchar = ' '; + + if (!PyArg_ParseTuple(args, "i|O&:rjust", &width, convert_uc, &fillchar)) return NULL; if (self->length >= width && PyUnicode_CheckExact(self)) { @@ -5569,7 +5601,7 @@ unicode_rjust(PyUnicodeObject *self, PyObject *args) return (PyObject*) self; } - return (PyObject*) pad(self, width - self->length, 0, ' '); + return (PyObject*) pad(self, width - self->length, 0, fillchar); } static PyObject* -- cgit v0.12