]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Backport the following changes:
authorWalter Dörwald <walter@livinglogic.de>
Mon, 22 Apr 2002 11:57:06 +0000 (11:57 +0000)
committerWalter Dörwald <walter@livinglogic.de>
Mon, 22 Apr 2002 11:57:06 +0000 (11:57 +0000)
Misc/NEWS 1.387->1.388
Lib/test/string_tests.py 1.10->1.11, 1.12->1.14,
Lib/test/test_unicode.py 1.50->1.51, 1.53->1.54, 1.55->1.56
Lib/test/test_string.py 1.15->1.16
Lib/string.py 1.61->1.63
Lib/test/test_userstring.py 1.5->1.6, 1.11, 1.12
Objects/stringobject.c 2.156->2.159
Objects/unicodeobject.c 2.137->2.139
Doc/lib/libstdtypes.tec 1.87->1.88

Add a method zfill to str, unicode and UserString
and change Lib/string.py accordingly
(see SF patch http://www.python.org/sf/536241)

This also adds Guido's fix to test_userstring.py
and the subinstance checks in test_string.py
and test_unicode.py.

Doc/lib/libstdtypes.tex
Lib/UserString.py
Lib/string.py
Lib/test/string_tests.py
Lib/test/test_string.py
Lib/test/test_unicode.py
Lib/test/test_userstring.py
Misc/NEWS
Objects/stringobject.c
Objects/unicodeobject.c

index adf953665b34c2c4da1deaec89a244a982e54c60..1edc8bb99c3a2958cad410d0a09f8d1275d01740 100644 (file)
@@ -689,6 +689,12 @@ must be a string of length 256.
 Return a copy of the string converted to uppercase.
 \end{methoddesc}
 
+\begin{methoddesc}[string]{zfill}{width}
+Return the numeric string left filled with zeros in a string
+of length \var{width}. The original string is returned if
+\var{width} is less than \code{len(\var{s})}.
+\end{methoddesc}
+
 
 \subsubsection{String Formatting Operations \label{typesseq-strings}}
 
index f4f5cab96ced91508bd9c77e6a9de604ba47215b..292e85242d8a8424fa276ffa79bf5e14542dc2ee 100755 (executable)
@@ -128,6 +128,7 @@ class UserString:
     def translate(self, *args):
         return self.__class__(self.data.translate(*args))
     def upper(self): return self.__class__(self.data.upper())
+    def zfill(self, width): return self.__class__(self.data.zfill(width))
 
 class MutableString(UserString):
     """mutable string objects
index a416530e5d9cd78a78fa77cba6bcc7ddd31a9e3e..cd9909e2661721c1a53277f1e82968a98901e4fc 100644 (file)
@@ -190,7 +190,10 @@ def rfind(s, *args):
 _float = float
 _int = int
 _long = long
-_StringType = type('')
+try:
+    _StringTypes = (str, unicode)
+except NameError:
+    _StringTypes = (str,)
 
 # Convert string to float
 def atof(s):
@@ -276,14 +279,9 @@ def zfill(x, width):
     of the specified width.  The string x is never truncated.
 
     """
-    if type(x) == type(''): s = x
-    else: s = `x`
-    n = len(s)
-    if n >= width: return s
-    sign = ''
-    if s[0] in ('-', '+'):
-        sign, s = s[0], s[1:]
-    return sign + '0'*(width-n) + s
+    if not isinstance(x, _StringTypes):
+        x = repr(x)
+    return x.zfill(width)
 
 # Expand tabs in a string.
 # Doesn't take non-printing chars into account, but does understand \n.
index 3a302c6670cafe20b553087c184e913ed5616c1c..180072c2fca40e9e0acc7e887f6f593dfdbd0c3a 100644 (file)
@@ -227,6 +227,19 @@ def run_method_tests(test):
     test('endswith', 'ab', 0, 'ab', 0, 1)
     test('endswith', 'ab', 0, 'ab', 0, 0)
 
+    test('zfill', '123', '123', 2)
+    test('zfill', '123', '123', 3)
+    test('zfill', '123', '0123', 4)
+    test('zfill', '+123', '+123', 3)
+    test('zfill', '+123', '+123', 4)
+    test('zfill', '+123', '+0123', 5)
+    test('zfill', '-123', '-123', 3)
+    test('zfill', '-123', '-123', 4)
+    test('zfill', '-123', '-0123', 5)
+    test('zfill', '', '000', 3)
+    test('zfill', '34', '34', 1)
+    test('zfill', '34', '0034', 4)
+
     # Encoding/decoding
     codecs = [('rot13', 'uryyb jbeyq'),
               ('base64', 'aGVsbG8gd29ybGQ=\n'),
index 4c5a60aa2cd898929542f020fd10666b4bb175ed..8f0ea47bd0a1396292d0186d28c876997eb4224b 100644 (file)
@@ -22,6 +22,25 @@ def test(name, input, output, *args):
     except:
         value = sys.exc_type
         f = name
+    if value == output:
+        # if the original is returned make sure that
+        # this doesn't happen with subclasses
+        if value is input:
+            class ssub(str):
+                def __repr__(self):
+                    return 'ssub(%r)' % str.__repr__(self)
+            input = ssub(input)
+            try:
+                f = getattr(input, name)
+                value = apply(f, args)
+            except AttributeError:
+                f = getattr(string, name)
+                value = apply(f, (input,) + args)
+            if value is input:
+                if verbose:
+                   print 'no'
+                print '*',f, `input`, `output`, `value`
+                return
     if value != output:
         if verbose:
             print 'no'
index df5d6159ba0b611a1f2316fdc7bcf62029d6ec0c..4e96752b76c477f3464bcb29bdecd38480275854 100644 (file)
@@ -6,7 +6,7 @@ Written by Marc-Andre Lemburg (mal@lemburg.com).
 
 """#"
 from test_support import verify, verbose, TestFailed
-import sys
+import sys, string
 
 if not sys.platform.startswith('java'):
     # Test basic sanity of repr()
@@ -204,6 +204,19 @@ if 0:
     test('capwords', u'abc\tdef\nghi', u'Abc Def Ghi')
     test('capwords', u'abc\t   def  \nghi', u'Abc Def Ghi')
 
+test('zfill', u'123', u'123', 2)
+test('zfill', u'123', u'123', 3)
+test('zfill', u'123', u'0123', 4)
+test('zfill', u'+123', u'+123', 3)
+test('zfill', u'+123', u'+123', 4)
+test('zfill', u'+123', u'+0123', 5)
+test('zfill', u'-123', u'-123', 3)
+test('zfill', u'-123', u'-123', 4)
+test('zfill', u'-123', u'-0123', 5)
+test('zfill', u'', u'000', 3)
+test('zfill', u'34', u'34', 1)
+test('zfill', u'34', u'00034', 5)
+
 # Comparisons:
 print 'Testing Unicode comparisons...',
 verify(u'abc' == 'abc')
index a8df84d7ba323e7492974b7e2c326b86df70ff14..86997ce3741e184aa05ccaeb9feedc6f5a5dc784 100755 (executable)
@@ -8,15 +8,15 @@ import string_tests
 from UserString import UserString
 
 if __name__ == "__main__":
-    verbose = 0
+    verbose = '-v' in sys.argv
 
 tested_methods = {}
 
-def test(methodname, input, *args):
+def test(methodname, input, output, *args):
     global tested_methods
     tested_methods[methodname] = 1
     if verbose:
-        print '%s.%s(%s) ' % (input, methodname, args),
+        print '%r.%s(%s)' % (input, methodname, ", ".join(map(repr, args))),
     u = UserString(input)
     objects = [input, u, UserString(u)]
     res = [""] * 3
@@ -24,22 +24,20 @@ def test(methodname, input, *args):
         object = objects[i]
         try:
             f = getattr(object, methodname)
-            res[i] = apply(f, args)
-        except:
-            res[i] = sys.exc_type
-    if res[0] != res[1]:
-        if verbose:
-            print 'no'
-        print `input`, f, `res[0]`, "<>", `res[1]`
-    else:
+        except AttributeError:
+            f = None
+            res[i] = AttributeError
+        else:
+            try:
+                res[i] = apply(f, args)
+            except:
+                res[i] = sys.exc_type
+    if res[0] == res[1] == res[2] == output:
         if verbose:
             print 'yes'
-    if res[1] != res[2]:
-        if verbose:
-            print 'no'
-        print `input`, f, `res[1]`, "<>", `res[2]`
     else:
         if verbose:
-            print 'yes'
+            print 'no'
+        print (methodname, input, output, args, res[0], res[1], res[2])
 
 string_tests.run_method_tests(test)
index 0507950048c07646d27fe097e9d1a734f7fc0153..48c9b321a6b3dcbbe5342cf8b78d7f7ed2e836b3 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -8,6 +8,10 @@ Core and builtins
   great many cyclic structures involving frames.  Reported on
   SourceForge as bug 543148.
 
+- A method zfill() was added to str and unicode, that fills a numeric
+  string to the left with zeros.  For example,
+  "+123".zfill(6) -> "+00123".
+
 - Complex numbers supported divmod() and the // and % operators, but
   these make no sense.  Since this was documented, they're being
   deprecated now.
index 95bc79abc12e9c3e982186c24584e1fbca16b01f..feb5947c3a59c03c0991fdf15eadc80f60bd24c1 100644 (file)
@@ -1,4 +1,3 @@
-
 /* String object implementation */
 
 #include "Python.h"
@@ -605,7 +604,8 @@ string_print(PyStringObject *op, FILE *fp, int flags)
 
        /* figure out which quote to use; single is preferred */
        quote = '\'';
-       if (strchr(op->ob_sval, '\'') && !strchr(op->ob_sval, '"'))
+       if (strchr(op->ob_sval, '\'') &&
+           !strchr(op->ob_sval, '"'))
                quote = '"';
 
        fputc(quote, fp);
@@ -649,7 +649,8 @@ string_repr(register PyStringObject *op)
 
                /* figure out which quote to use; single is preferred */
                quote = '\'';
-               if (strchr(op->ob_sval, '\'') && !strchr(op->ob_sval, '"'))
+               if (strchr(op->ob_sval, '\'') &&
+                   !strchr(op->ob_sval, '"'))
                        quote = '"';
 
                p = PyString_AS_STRING(v);
@@ -2414,6 +2415,52 @@ string_center(PyStringObject *self, PyObject *args)
     return pad(self, left, marg - left, ' ');
 }
 
+static char zfill__doc__[] =
+"S.zfill(width) -> string\n"
+"\n"
+"Pad a numeric string S with zeros on the left, to fill a field\n"
+"of the specified width.  The string S is never truncated.";
+
+static PyObject *
+string_zfill(PyStringObject *self, PyObject *args)
+{
+    int fill;
+    PyObject *s;
+    char *p;
+
+    int width;
+    if (!PyArg_ParseTuple(args, "i:zfill", &width))
+        return NULL;
+
+    if (PyString_GET_SIZE(self) >= width) {
+        if (PyString_CheckExact(self)) {
+            Py_INCREF(self);
+            return (PyObject*) self;
+        }
+        else
+            return PyString_FromStringAndSize(
+                PyString_AS_STRING(self),
+                PyString_GET_SIZE(self)
+            );
+    }
+
+    fill = width - PyString_GET_SIZE(self);
+
+    s = pad(self, fill, 0, '0');
+
+    if (s == NULL)
+        return NULL;
+
+    p = PyString_AS_STRING(s);
+    if (p[fill] == '+' || p[fill] == '-') {
+        /* move sign to beginning of string */
+        p[0] = p[fill];
+        p[fill] = '0';
+    }
+
+    return (PyObject*) s;
+}
+
 static char isspace__doc__[] =
 "S.isspace() -> int\n"
 "\n"
@@ -2743,9 +2790,11 @@ string_methods[] = {
        {"istitle", (PyCFunction)string_istitle, METH_NOARGS, istitle__doc__},
        {"isalpha", (PyCFunction)string_isalpha, METH_NOARGS, isalpha__doc__},
        {"isalnum", (PyCFunction)string_isalnum, METH_NOARGS, isalnum__doc__},
-       {"capitalize", (PyCFunction)string_capitalize,  METH_NOARGS, capitalize__doc__},
+       {"capitalize", (PyCFunction)string_capitalize,  METH_NOARGS,
+        capitalize__doc__},
        {"count",      (PyCFunction)string_count,       METH_VARARGS, count__doc__},
-       {"endswith",   (PyCFunction)string_endswith,    METH_VARARGS, endswith__doc__},
+       {"endswith",   (PyCFunction)string_endswith,    METH_VARARGS,
+        endswith__doc__},
        {"find",       (PyCFunction)string_find,        METH_VARARGS, find__doc__},
        {"index",      (PyCFunction)string_index,       METH_VARARGS, index__doc__},
        {"lstrip",     (PyCFunction)string_lstrip,      METH_VARARGS, lstrip__doc__},
@@ -2753,21 +2802,24 @@ string_methods[] = {
        {"rfind",       (PyCFunction)string_rfind,      METH_VARARGS, rfind__doc__},
        {"rindex",      (PyCFunction)string_rindex,     METH_VARARGS, rindex__doc__},
        {"rstrip",      (PyCFunction)string_rstrip,     METH_VARARGS, rstrip__doc__},
-       {"startswith",  (PyCFunction)string_startswith, METH_VARARGS, startswith__doc__},
+       {"startswith",  (PyCFunction)string_startswith, METH_VARARGS,
+        startswith__doc__},
        {"strip",       (PyCFunction)string_strip,      METH_VARARGS, strip__doc__},
-       {"swapcase",    (PyCFunction)string_swapcase,   METH_NOARGS, swapcase__doc__},
-       {"translate",   (PyCFunction)string_translate,  METH_VARARGS, translate__doc__},
+       {"swapcase",    (PyCFunction)string_swapcase,   METH_NOARGS,
+        swapcase__doc__},
+       {"translate",   (PyCFunction)string_translate,  METH_VARARGS,
+        translate__doc__},
        {"title",       (PyCFunction)string_title,      METH_NOARGS, title__doc__},
        {"ljust",       (PyCFunction)string_ljust,      METH_VARARGS, ljust__doc__},
        {"rjust",       (PyCFunction)string_rjust,      METH_VARARGS, rjust__doc__},
        {"center",      (PyCFunction)string_center,     METH_VARARGS, center__doc__},
+       {"zfill",       (PyCFunction)string_zfill,      METH_VARARGS, zfill__doc__},
        {"encode",      (PyCFunction)string_encode,     METH_VARARGS, encode__doc__},
        {"decode",      (PyCFunction)string_decode,     METH_VARARGS, decode__doc__},
-       {"expandtabs",  (PyCFunction)string_expandtabs, METH_VARARGS, expandtabs__doc__},
-       {"splitlines",  (PyCFunction)string_splitlines, METH_VARARGS, splitlines__doc__},
-#if 0
-       {"zfill",       (PyCFunction)string_zfill,      METH_VARARGS, zfill__doc__},
-#endif
+       {"expandtabs",  (PyCFunction)string_expandtabs, METH_VARARGS,
+        expandtabs__doc__},
+       {"splitlines",  (PyCFunction)string_splitlines, METH_VARARGS,
+        splitlines__doc__},
        {NULL,     NULL}                     /* sentinel */
 };
 
@@ -3262,7 +3314,8 @@ PyString_Format(PyObject *format, PyObject *args)
                        char *pbuf;
                        int sign;
                        int len;
-                       char formatbuf[FORMATBUFLEN]; /* For format{float,int,char}() */
+                       char formatbuf[FORMATBUFLEN];
+                            /* For format{float,int,char}() */
 #ifdef Py_USING_UNICODE
                        char *fmt_start = fmt;
                        int argidx_start = argidx;
@@ -3460,7 +3513,8 @@ PyString_Format(PyObject *format, PyObject *args)
                                }
                                else {
                                        pbuf = formatbuf;
-                                       len = formatint(pbuf, sizeof(formatbuf),
+                                       len = formatint(pbuf,
+                                                       sizeof(formatbuf),
                                                        flags, prec, c, v);
                                        if (len < 0)
                                                goto error;
@@ -3476,7 +3530,8 @@ PyString_Format(PyObject *format, PyObject *args)
                        case 'g':
                        case 'G':
                                pbuf = formatbuf;
-                               len = formatfloat(pbuf, sizeof(formatbuf), flags, prec, c, v);
+                               len = formatfloat(pbuf, sizeof(formatbuf),
+                                         flags, prec, c, v);
                                if (len < 0)
                                        goto error;
                                sign = 1;
index 5a8777b39643892d40428e84f6a3ad41d282a480..c797be01b87bd27e4328ff25a5fa3be3d8b32122 100644 (file)
@@ -4810,7 +4810,6 @@ unicode_upper(PyUnicodeObject *self)
     return fixup(self, fixupper);
 }
 
-#if 0
 static char zfill__doc__[] =
 "S.zfill(width) -> unicode\n\
 \n\
@@ -4828,14 +4827,24 @@ unicode_zfill(PyUnicodeObject *self, PyObject *args)
         return NULL;
 
     if (self->length >= width) {
-        Py_INCREF(self);
-        return (PyObject*) self;
+        if (PyUnicode_CheckExact(self)) {
+            Py_INCREF(self);
+            return (PyObject*) self;
+        }
+        else
+            return PyUnicode_FromUnicode(
+                PyUnicode_AS_UNICODE(self),
+                PyUnicode_GET_SIZE(self)
+            );
     }
 
     fill = width - self->length;
 
     u = pad(self, fill, 0, '0');
 
+    if (u == NULL)
+        return NULL;
+
     if (u->str[fill] == '+' || u->str[fill] == '-') {
         /* move sign to beginning of string */
         u->str[0] = u->str[fill];
@@ -4844,7 +4853,6 @@ unicode_zfill(PyUnicodeObject *self, PyObject *args)
 
     return (PyObject*) u;
 }
-#endif
 
 #if 0
 static PyObject*
@@ -4956,8 +4964,8 @@ static PyMethodDef unicode_methods[] = {
     {"isnumeric", (PyCFunction) unicode_isnumeric, METH_NOARGS, isnumeric__doc__},
     {"isalpha", (PyCFunction) unicode_isalpha, METH_NOARGS, isalpha__doc__},
     {"isalnum", (PyCFunction) unicode_isalnum, METH_NOARGS, isalnum__doc__},
-#if 0
     {"zfill", (PyCFunction) unicode_zfill, METH_VARARGS, zfill__doc__},
+#if 0
     {"capwords", (PyCFunction) unicode_capwords, METH_NOARGS, capwords__doc__},
 #endif