Skip to content

Commit 49c5e74

Browse files
committed
fix: clamp n to len(pwcs) in wcswidth/wcstwidth to avoid IndexError
Passing n > len(pwcs) to wcswidth() or wcstwidth() causes an IndexError when the loop index reaches the end of the string, because `end` was set to n directly. Fix: `end = min(n, len(pwcs))` so that n larger than the string length is treated the same as measuring the whole string, which is the natural Python semantics for sized strings. Adds a regression test covering ASCII, wide characters, and ZWJ clusters.
1 parent d1c99fe commit 49c5e74

2 files changed

Lines changed: 18 additions & 2 deletions

File tree

tests/test_core.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,22 @@ def test_zwj_at_end_of_string():
497497
assert wcwidth.wcswidth('a\u200D') == 1
498498

499499

500+
def test_wcswidth_n_exceeds_length():
501+
"""
502+
wcswidth() with n > len(string) returns same as n=None.
503+
504+
Passing n larger than the string length should not raise IndexError;
505+
it should behave identically to measuring the whole string.
506+
"""
507+
# ASCII string
508+
assert wcwidth.wcswidth('hello', 10) == 5
509+
# Wide characters
510+
assert wcwidth.wcswidth('\u30B3\u30F3', 5) == 4
511+
# ZWJ cluster
512+
family = '\U0001F468\u200D\U0001F469\u200D\U0001F467'
513+
assert wcwidth.wcswidth(family, len(family) + 1) == wcwidth.wcswidth(family)
514+
515+
500516
def test_soft_hyphen():
501517
# Test SOFT HYPHEN, category 'Cf' usually are zero-width, but most
502518
# implementations agree to draw it was '1' cell, visually

wcwidth/_wcswidth.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ def wcswidth(
9898

9999
_wcwidth = wcwidth if ambiguous_width == 1 else lambda c: wcwidth(c, 'auto', ambiguous_width)
100100

101-
end = len(pwcs) if n is None else n
101+
end = len(pwcs) if n is None else min(n, len(pwcs))
102102
total_width = 0
103103
idx = 0
104104

@@ -262,7 +262,7 @@ def wcstwidth(
262262
# Select wcwidth call pattern for best lru_cache performance
263263
_wcwidth = wcwidth if ambiguous_width == 1 else lambda c: wcwidth(c, 'auto', ambiguous_width)
264264

265-
end = len(pwcs) if n is None else n
265+
end = len(pwcs) if n is None else min(n, len(pwcs))
266266
total_width = 0
267267
idx = 0
268268

0 commit comments

Comments
 (0)