From 005550e92a4308cf944abbae3a46ad1054a1330d Mon Sep 17 00:00:00 2001 From: Md Kaif <119096690+LordAizen1@users.noreply.github.com> Date: Tue, 21 Jul 2026 16:39:11 +0530 Subject: [PATCH] fix(str): zfill should preserve a leading sign (#533) zfill writes the padding zeros before the whole string, so a leading + or - ends up in the middle of the result instead of staying in front. For example "-5".zfill(4) gave '00-5' where CPython gives '-005'. CPython inserts the padding after the sign character, and the sign counts toward the requested width. Write the sign first, then the zeros, then the rest of the string. delta is still computed before this, so the total length is unchanged. The existing tests only covered unsigned strings, which is why this went unnoticed. Added three asserts alongside them. --- src/bindings/py_str.c | 6 ++++++ tests/041_str.py | 3 +++ 2 files changed, 9 insertions(+) diff --git a/src/bindings/py_str.c b/src/bindings/py_str.c index 7b71de89..ea300b72 100644 --- a/src/bindings/py_str.c +++ b/src/bindings/py_str.c @@ -447,6 +447,12 @@ static bool str_zfill(int argc, py_Ref argv) { } c11_sbuf buf; c11_sbuf__ctor(&buf); + // a leading sign is kept in front; the padding goes after it + if(self.size > 0 && (self.data[0] == '+' || self.data[0] == '-')) { + c11_sbuf__write_char(&buf, self.data[0]); + self.data++; + self.size--; + } for(int i = 0; i < delta; i++) { c11_sbuf__write_char(&buf, '0'); } diff --git a/tests/041_str.py b/tests/041_str.py index 475d15c2..f7fda43a 100644 --- a/tests/041_str.py +++ b/tests/041_str.py @@ -112,6 +112,9 @@ assert s2.join( seq ) == "runoob" assert 'x'.zfill(5) == '0000x' assert '568'.zfill(1) == '568' +assert '-5'.zfill(4) == '-005' +assert '+5'.zfill(4) == '+005' +assert '-'.zfill(3) == '-00' num = 6 assert str(num) == '6'