Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d68af8f

Browse files
committed
Merged revisions 64984 via svnmerge from
svn+ssh://[email protected]/python/trunk ........ r64984 | eric.smith | 2008-07-15 20:11:49 -0400 (Tue, 15 Jul 2008) | 1 line Complete issue 3083: add alternate (#) formatting to bin, oct, hex in str.format(). ........
1 parent f70e195 commit d68af8f

4 files changed

Lines changed: 89 additions & 33 deletions

File tree

Doc/library/string.rst

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ result as if you had called :func:`str` on the value.
294294
The general form of a *standard format specifier* is:
295295

296296
.. productionlist:: sf
297-
format_spec: [[`fill`]`align`][`sign`][0][`width`][.`precision`][`type`]
297+
format_spec: [[`fill`]`align`][`sign`][#][0][`width`][.`precision`][`type`]
298298
fill: <a character other than '}'>
299299
align: "<" | ">" | "=" | "^"
300300
sign: "+" | "-" | " "
@@ -348,6 +348,10 @@ following:
348348
| | positive numbers, and a minus sign on negative numbers. |
349349
+---------+----------------------------------------------------------+
350350

351+
The ``'#'`` option is only valid for integers, and only for binary,
352+
octal, or decimal output. If present, it specifies that the output
353+
will be prefixed by ``'0b'``, ``'0o'``, or ``'0x'``, respectively.
354+
351355
*width* is a decimal integer defining the minimum field width. If not
352356
specified, then the field width will be determined by the content.
353357

@@ -368,7 +372,7 @@ The available integer presentation types are:
368372
+---------+----------------------------------------------------------+
369373
| Type | Meaning |
370374
+=========+==========================================================+
371-
| ``'b'`` | Binary. Outputs the number in base 2. |
375+
| ``'b'`` | Binary format. Outputs the number in base 2. |
372376
+---------+----------------------------------------------------------+
373377
| ``'c'`` | Character. Converts the integer to the corresponding |
374378
| | unicode character before printing. |

Lib/test/test_types.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,8 @@ def test(i, format_spec, result):
301301
test(-1, "-#5b", ' -0b1')
302302
test(1, "+#5b", ' +0b1')
303303
test(100, "+#b", '+0b1100100')
304-
# test(100, "#012b", '0b001100100')
304+
test(100, "#012b", '0b0001100100')
305+
test(-100, "#012b", '-0b001100100')
305306

306307
test(0, "#o", '0o0')
307308
test(0, "-#o", '0o0')
@@ -310,6 +311,8 @@ def test(i, format_spec, result):
310311
test(-1, "-#5o", ' -0o1')
311312
test(1, "+#5o", ' +0o1')
312313
test(100, "+#o", '+0o144')
314+
test(100, "#012o", '0o0000000144')
315+
test(-100, "#012o", '-0o000000144')
313316

314317
test(0, "#x", '0x0')
315318
test(0, "-#x", '0x0')
@@ -318,6 +321,10 @@ def test(i, format_spec, result):
318321
test(-1, "-#5x", ' -0x1')
319322
test(1, "+#5x", ' +0x1')
320323
test(100, "+#x", '+0x64')
324+
test(100, "#012x", '0x0000000064')
325+
test(-100, "#012x", '-0x000000064')
326+
test(123456, "#012x", '0x000001e240')
327+
test(-123456, "#012x", '-0x00001e240')
321328

322329
test(0, "#X", '0X0')
323330
test(0, "-#X", '0X0')
@@ -326,6 +333,10 @@ def test(i, format_spec, result):
326333
test(-1, "-#5X", ' -0X1')
327334
test(1, "+#5X", ' +0X1')
328335
test(100, "+#X", '+0X64')
336+
test(100, "#012X", '0X0000000064')
337+
test(-100, "#012X", '-0X000000064')
338+
test(123456, "#012X", '0X000001E240')
339+
test(-123456, "#012X", '-0X00001E240')
329340

330341
# make sure these are errors
331342

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ What's new in Python 3.0b2?
1212
Core and Builtins
1313
-----------------
1414

15+
- Issue #3083: Add alternate (#) formatting for bin, oct, hex output
16+
for str.format(). This adds the prefix 0b, 0o, or 0x, respectively.
17+
1518
- Issue #3280: like chr(), the "%c" format now accepts unicode code points
1619
beyond the Basic Multilingual Plane (above 0xffff) on all configurations. On
1720
"narrow Unicode" builds, the result is a string of 2 code units, forming a

Objects/stringlib/formatter.h

Lines changed: 68 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,13 @@ parse_internal_render_format_spec(STRINGLIB_CHAR *format_spec,
147147
#endif
148148
}
149149

150+
/* If the next character is #, we're in alternate mode. This only
151+
applies to integers. */
152+
if (end-ptr >= 1 && ptr[0] == '#') {
153+
format->alternate = 1;
154+
++ptr;
155+
}
156+
150157
/* The special case for 0-padding (backwards compat) */
151158
if (format->fill_char == '\0' && end-ptr >= 1 && ptr[0] == '0') {
152159
format->fill_char = '0';
@@ -156,13 +163,6 @@ parse_internal_render_format_spec(STRINGLIB_CHAR *format_spec,
156163
++ptr;
157164
}
158165

159-
/* If the next character is #, we're in alternate mode. This only
160-
applies to integers. */
161-
if (end-ptr >= 1 && ptr[0] == '#') {
162-
format->alternate = 1;
163-
++ptr;
164-
}
165-
166166
/* XXX add error checking */
167167
specified_width = get_integer(&ptr, end, &format->width);
168168

@@ -211,9 +211,10 @@ parse_internal_render_format_spec(STRINGLIB_CHAR *format_spec,
211211
/************************************************************************/
212212

213213
/* describes the layout for an integer, see the comment in
214-
_calc_integer_widths() for details */
214+
calc_number_widths() for details */
215215
typedef struct {
216216
Py_ssize_t n_lpadding;
217+
Py_ssize_t n_prefix;
217218
Py_ssize_t n_spadding;
218219
Py_ssize_t n_rpadding;
219220
char lsign;
@@ -234,6 +235,7 @@ calc_number_widths(NumberFieldWidths *r, STRINGLIB_CHAR actual_sign,
234235
const InternalFormatSpec *format)
235236
{
236237
r->n_lpadding = 0;
238+
r->n_prefix = 0;
237239
r->n_spadding = 0;
238240
r->n_rpadding = 0;
239241
r->lsign = '\0';
@@ -288,21 +290,25 @@ calc_number_widths(NumberFieldWidths *r, STRINGLIB_CHAR actual_sign,
288290
}
289291
}
290292

293+
r->n_prefix = n_prefix;
294+
291295
/* now the number of padding characters */
292296
if (format->width == -1) {
293297
/* no padding at all, nothing to do */
294298
}
295299
else {
296300
/* see if any padding is needed */
297-
if (r->n_lsign + n_digits + r->n_rsign >= format->width) {
301+
if (r->n_lsign + n_digits + r->n_rsign +
302+
r->n_prefix >= format->width) {
298303
/* no padding needed, we're already bigger than the
299304
requested width */
300305
}
301306
else {
302307
/* determine which of left, space, or right padding is
303308
needed */
304309
Py_ssize_t padding = format->width -
305-
(r->n_lsign + n_digits + r->n_rsign);
310+
(r->n_lsign + r->n_prefix +
311+
n_digits + r->n_rsign);
306312
if (format->align == '<')
307313
r->n_rpadding = padding;
308314
else if (format->align == '>')
@@ -317,18 +323,19 @@ calc_number_widths(NumberFieldWidths *r, STRINGLIB_CHAR actual_sign,
317323
r->n_lpadding = padding;
318324
}
319325
}
320-
r->n_total = r->n_lpadding + r->n_lsign + r->n_spadding +
321-
n_digits + r->n_rsign + r->n_rpadding;
326+
r->n_total = r->n_lpadding + r->n_lsign + r->n_prefix +
327+
r->n_spadding + n_digits + r->n_rsign + r->n_rpadding;
322328
}
323329

324330
/* fill in the non-digit parts of a numbers's string representation,
325-
as determined in _calc_integer_widths(). returns the pointer to
331+
as determined in calc_number_widths(). returns the pointer to
326332
where the digits go. */
327333
static STRINGLIB_CHAR *
328334
fill_non_digits(STRINGLIB_CHAR *p_buf, const NumberFieldWidths *spec,
329-
Py_ssize_t n_digits, STRINGLIB_CHAR fill_char)
335+
STRINGLIB_CHAR *prefix, Py_ssize_t n_digits,
336+
STRINGLIB_CHAR fill_char)
330337
{
331-
STRINGLIB_CHAR* p_digits;
338+
STRINGLIB_CHAR *p_digits;
332339

333340
if (spec->n_lpadding) {
334341
STRINGLIB_FILL(p_buf, fill_char, spec->n_lpadding);
@@ -337,6 +344,12 @@ fill_non_digits(STRINGLIB_CHAR *p_buf, const NumberFieldWidths *spec,
337344
if (spec->n_lsign == 1) {
338345
*p_buf++ = spec->lsign;
339346
}
347+
if (spec->n_prefix) {
348+
memmove(p_buf,
349+
prefix,
350+
spec->n_prefix * sizeof(STRINGLIB_CHAR));
351+
p_buf += spec->n_prefix;
352+
}
340353
if (spec->n_spadding) {
341354
STRINGLIB_FILL(p_buf, fill_char, spec->n_spadding);
342355
p_buf += spec->n_spadding;
@@ -477,6 +490,8 @@ format_int_or_long_internal(PyObject *value, const InternalFormatSpec *format,
477490
Py_ssize_t n_grouping_chars = 0; /* Count of additional chars to
478491
allocate, used for 'n'
479492
formatting. */
493+
Py_ssize_t n_prefix = 0; /* Count of prefix chars, (e.g., '0x') */
494+
STRINGLIB_CHAR *prefix = NULL;
480495
NumberFieldWidths spec;
481496
long x;
482497

@@ -534,19 +549,16 @@ format_int_or_long_internal(PyObject *value, const InternalFormatSpec *format,
534549
switch (format->type) {
535550
case 'b':
536551
base = 2;
537-
if (!format->alternate)
538-
leading_chars_to_skip = 2; /* 0b */
552+
leading_chars_to_skip = 2; /* 0b */
539553
break;
540554
case 'o':
541555
base = 8;
542-
if (!format->alternate)
543-
leading_chars_to_skip = 2; /* 0o */
556+
leading_chars_to_skip = 2; /* 0o */
544557
break;
545558
case 'x':
546559
case 'X':
547560
base = 16;
548-
if (!format->alternate)
549-
leading_chars_to_skip = 2; /* 0x */
561+
leading_chars_to_skip = 2; /* 0x */
550562
break;
551563
default: /* shouldn't be needed, but stops a compiler warning */
552564
case 'd':
@@ -555,6 +567,11 @@ format_int_or_long_internal(PyObject *value, const InternalFormatSpec *format,
555567
break;
556568
}
557569

570+
/* The number of prefix chars is the same as the leading
571+
chars to skip */
572+
if (format->alternate)
573+
n_prefix = leading_chars_to_skip;
574+
558575
/* Do the hard part, converting to a string in a given base */
559576
tmp = tostring(value, base);
560577
if (tmp == NULL)
@@ -563,6 +580,8 @@ format_int_or_long_internal(PyObject *value, const InternalFormatSpec *format,
563580
pnumeric_chars = STRINGLIB_STR(tmp);
564581
n_digits = STRINGLIB_LEN(tmp);
565582

583+
prefix = pnumeric_chars;
584+
566585
/* Remember not to modify what pnumeric_chars points to. it
567586
might be interned. Only modify it after we copy it into a
568587
newly allocated output buffer. */
@@ -571,6 +590,7 @@ format_int_or_long_internal(PyObject *value, const InternalFormatSpec *format,
571590
and skip it */
572591
sign = pnumeric_chars[0];
573592
if (sign == '-') {
593+
++prefix;
574594
++leading_chars_to_skip;
575595
}
576596

@@ -586,43 +606,61 @@ format_int_or_long_internal(PyObject *value, const InternalFormatSpec *format,
586606
0, &n_grouping_chars, 0);
587607

588608
/* Calculate the widths of the various leading and trailing parts */
589-
calc_number_widths(&spec, sign, 0, n_digits + n_grouping_chars, format);
609+
calc_number_widths(&spec, sign, n_prefix, n_digits + n_grouping_chars,
610+
format);
590611

591612
/* Allocate a new string to hold the result */
592613
result = STRINGLIB_NEW(NULL, spec.n_total);
593614
if (!result)
594615
goto done;
595616
p = STRINGLIB_STR(result);
596617

618+
/* XXX There is too much magic here regarding the internals of
619+
spec and the location of the prefix and digits. It would be
620+
better if calc_number_widths returned a number of logical
621+
offsets into the buffer, and those were used. Maybe in a
622+
future code cleanup. */
623+
597624
/* Fill in the digit parts */
598-
n_leading_chars = spec.n_lpadding + spec.n_lsign + spec.n_spadding;
625+
n_leading_chars = spec.n_lpadding + spec.n_lsign +
626+
spec.n_prefix + spec.n_spadding;
599627
memmove(p + n_leading_chars,
600628
pnumeric_chars,
601629
n_digits * sizeof(STRINGLIB_CHAR));
602630

603-
/* If type is 'X', convert to uppercase */
631+
/* If type is 'X', convert the filled in digits to uppercase */
604632
if (format->type == 'X') {
605633
Py_ssize_t t;
606634
for (t = 0; t < n_digits; ++t)
607635
p[t + n_leading_chars] = STRINGLIB_TOUPPER(p[t + n_leading_chars]);
608636
}
609637

610-
/* Insert the grouping, if any, after the uppercasing of 'X', so we can
611-
ensure that grouping chars won't be affected. */
638+
/* Insert the grouping, if any, after the uppercasing of the digits, so
639+
we can ensure that grouping chars won't be affected. */
612640
if (n_grouping_chars) {
613641
/* We know this can't fail, since we've already
614642
reserved enough space. */
615643
STRINGLIB_CHAR *pstart = p + n_leading_chars;
616644
int r = STRINGLIB_GROUPING(pstart, n_digits, n_digits,
617-
spec.n_total+n_grouping_chars-n_leading_chars,
618-
NULL, 0);
645+
spec.n_total+n_grouping_chars-n_leading_chars,
646+
NULL, 0);
619647
assert(r);
620648
}
621649

622650
/* Fill in the non-digit parts (padding, sign, etc.) */
623-
fill_non_digits(p, &spec, n_digits + n_grouping_chars,
651+
fill_non_digits(p, &spec, prefix, n_digits + n_grouping_chars,
624652
format->fill_char == '\0' ? ' ' : format->fill_char);
625653

654+
/* If type is 'X', uppercase the prefix. This has to be done after the
655+
prefix is filled in by fill_non_digits */
656+
if (format->type == 'X') {
657+
Py_ssize_t t;
658+
for (t = 0; t < n_prefix; ++t)
659+
p[t + spec.n_lpadding + spec.n_lsign] =
660+
STRINGLIB_TOUPPER(p[t + spec.n_lpadding + spec.n_lsign]);
661+
}
662+
663+
626664
done:
627665
Py_XDECREF(tmp);
628666
return result;
@@ -768,7 +806,7 @@ format_float_internal(PyObject *value,
768806
goto done;
769807

770808
/* Fill in the non-digit parts (padding, sign, etc.) */
771-
fill_non_digits(STRINGLIB_STR(result), &spec, n_digits,
809+
fill_non_digits(STRINGLIB_STR(result), &spec, NULL, n_digits,
772810
format->fill_char == '\0' ? ' ' : format->fill_char);
773811

774812
/* fill in the digit parts */

0 commit comments

Comments
 (0)