From 24dc1b7b484bc0f00f5543e4b2ff7c15a3f5deb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Lucas?= Date: Sat, 8 Aug 2026 17:03:09 -0300 Subject: [PATCH] Anchor the utf-8-variants regexes at the true end of the buffer Python's $ also matches before a trailing newline, so a \n at the end of the input was consumed as part of a CESU-8 sequence or a Java null. Use \Z, which only matches at the very end, keeping the intent for truncated input in the streaming decoder. Fixes #236 --- ftfy/bad_codecs/utf8_variants.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ftfy/bad_codecs/utf8_variants.py b/ftfy/bad_codecs/utf8_variants.py index eaac3c1..f1c0f3f 100644 --- a/ftfy/bad_codecs/utf8_variants.py +++ b/ftfy/bad_codecs/utf8_variants.py @@ -58,11 +58,11 @@ CESU8_EXPR = ( b"(" b"\xed" - b"([\xa0-\xaf]|$)" - b"([\x80-\xbf]|$)" - b"(\xed|$)" - b"([\xb0-\xbf]|$)" - b"([\x80-\xbf]|$)" + b"([\xa0-\xaf]|\\Z)" + b"([\x80-\xbf]|\\Z)" + b"(\xed|\\Z)" + b"([\xb0-\xbf]|\\Z)" + b"([\x80-\xbf]|\\Z)" b")" ) @@ -70,11 +70,11 @@ # This expression matches isolated surrogate characters that aren't # CESU-8, which have to be handled carefully on Python 2. -SURROGATE_EXPR = b"(\xed([\xa0-\xbf]|$)([\x80-\xbf]|$))" +SURROGATE_EXPR = b"(\xed([\xa0-\xbf]|\\Z)([\x80-\xbf]|\\Z))" # This expression matches the Java encoding of U+0, including if it's # truncated and we need more bytes. -NULL_EXPR = b"(\xc0(\x80|$))" +NULL_EXPR = b"(\xc0(\x80|\\Z))" # This regex matches cases that we need to decode differently from # standard UTF-8.