diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py index 7b130ca..ad54b08 100644 --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -1451,6 +1451,13 @@ class UnicodeTest(string_tests.CommonTest, 'string, got a non-ASCII byte: 0xe9$', PyUnicode_FromFormat, b'unicode\xe9=%s', 'ascii') + # test formats + self.assertEqual(PyUnicode_FromFormat(b'%'), '%') + self.assertEqual(PyUnicode_FromFormat(b'%%'), '%') + self.assertEqual(PyUnicode_FromFormat(b'%%s'), '%s') + self.assertEqual(PyUnicode_FromFormat(b'[%%]'), '[%]') + self.assertEqual(PyUnicode_FromFormat(b'%%%s', b'abc'), '%abc') + # other tests text = PyUnicode_FromFormat(b'%%A:%A', 'abc\xe9\uabcd\U0010ffff') self.assertEqual(text, r"%A:'abc\xe9\uabcd\U0010ffff'") diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 4567196..cb69d86 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -750,14 +750,15 @@ PyUnicode_FromFormatV(const char *format, va_list vargs) * result in an array) */ for (f = format; *f; f++) { if (*f == '%') { - if (*(f+1)=='%') + if (f[1] == '%') { + f++; continue; + } if (*(f+1)=='S' || *(f+1)=='R' || *(f+1)=='A') ++callcount; - while (Py_ISDIGIT((unsigned)*f)) - width = (width*10) + *f++ - '0'; - while (*++f && *f != '%' && !Py_ISALPHA((unsigned)*f)) - ; + /* skip width or width.precision (eg. "1.2" of "%1.2f") */ + while (!Py_ISALPHA((unsigned)*f) && f[1] != '%' && f[1] != '\0') + ++f; if (*f == 's') ++callcount; } @@ -789,8 +790,9 @@ PyUnicode_FromFormatV(const char *format, va_list vargs) width = 0; while (Py_ISDIGIT((unsigned)*f)) width = (width*10) + *f++ - '0'; - while (*++f && *f != '%' && !Py_ISALPHA((unsigned)*f)) - ; + /* skip .precision (eg. ".2" of "%1.2f") */ + while (!Py_ISALPHA((unsigned)*f) && f[1] != '%' && f[1] != '\0') + ++f; /* skip the 'l' or 'z' in {%ld, %zd, %lu, %zu} since * they don't affect the amount of space we reserve. @@ -817,6 +819,7 @@ PyUnicode_FromFormatV(const char *format, va_list vargs) /* fall through... */ case '%': n++; + f++; break; case 'd': case 'u': case 'i': case 'x': (void) va_arg(count, int);