Path: csiph.com!fu-berlin.de!uni-berlin.de!not-for-mail From: Random832 Newsgroups: comp.lang.python Subject: Re: Processing text data with different encodings Date: Tue, 28 Jun 2016 11:52:18 -0400 Lines: 43 Message-ID: References: <1467129138.2539971.650945673.4DB27682@webmail.messagingengine.com> Mime-Version: 1.0 Content-Type: text/plain Content-Transfer-Encoding: 7bit X-Trace: news.uni-berlin.de AjqbDYtqsJfCmXKSrWkMJQF5IPktjn61hTp9AypAOfyQ== Return-Path: X-Original-To: python-list@python.org Delivered-To: python-list@mail.python.org X-Spam-Status: OK 0.001 X-Spam-Evidence: '*H*': 1.00; '*S*': 0.00; 'subject:text': 0.04; 'context': 0.05; 'failing': 0.05; 'sufficient': 0.05; 'character,': 0.07; 'utf-8': 0.07; 'codecs': 0.09; 'input,': 0.09; 'received:internal': 0.09; 'def': 0.13; 'cp1252': 0.16; 'decode': 0.16; 'encodings,': 0.16; 'idx': 0.16; 'message- id:@webmail.messagingengine.com': 0.16; 'received:10.202': 0.16; 'received:10.202.2': 0.16; 'received:66.111': 0.16; 'received:66.111.4': 0.16; 'received:66.111.4.27': 0.16; 'received:io': 0.16; 'received:messagingengine.com': 0.16; 'received:out3-smtp.messagingengine.com': 0.16; 'received:psf.io': 0.16; 'sufficient,': 0.16; 'vanishingly': 0.16; 'wrote:': 0.16; 'byte': 0.18; 'bytes': 0.18; 'instance,': 0.18; 'try:': 0.18; 'ascii': 0.22; "python's": 0.23; 'import': 0.24; 'skip:b 30': 0.24; 'header:In-Reply-To:1': 0.24; "doesn't": 0.26; 'chris': 0.26; 'error': 0.27; 'equivalent': 0.27; 'not.': 0.27; 'correct': 0.28; 'boundary': 0.29; 'sensible': 0.29; 'guess': 0.31; 'probably': 0.31; 'run': 0.33; 'problem': 0.33; 'doubt': 0.33; 'tue,': 0.34; 'except': 0.34; 'that,': 0.34; 'skip:c 30': 0.35; 'done': 0.35; 'something': 0.35; 'but': 0.36; 'lines': 0.36; '(i.e.': 0.36; 'to:addr:python-list': 0.36; 'subject:: ': 0.37; 'received:10': 0.37; 'two': 0.37; 'display': 0.37; 'difference': 0.38; 'received:66': 0.38; 'anything': 0.38; 'someone': 0.38; 'mean': 0.38; 'to:addr:python.org': 0.40; 'subject:with': 0.40; 'skip:u 10': 0.61; 'header:Message-Id:1': 0.61; 'provide': 0.61; 'you.': 0.64; 'between': 0.65; 'results': 0.66; 'detecting': 0.84; 'fonts': 0.84; 'fortunate': 0.84; 'fortunately': 0.84; 'japanese.': 0.84; "op's": 0.84; "there'll": 0.84; 'mean.': 0.91 DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=fastmail.com; h= content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to:x-sasl-enc :x-sasl-enc; s=mesmtp; bh=mg4n9zmNEvdWu6+obgDVQtVWYB8=; b=4Vtc07 fvpQZGZFELip8eDMWFaPiEQGnFLEHy7XJuwxyUGeeQ8x9yQeh834aHXh0Glkw5Qs 6K/lhQ9UEtn92y/Cvl/BV+DN4zAW3pf+bG4mCEyOEXIgmjXXnui/fhVndeN3sb+s FUBdv/T++9oX6UVHzP0Rh6RwM44O0pAjuJ1kA= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d= messagingengine.com; h=content-transfer-encoding:content-type :date:from:in-reply-to:message-id:mime-version:references :subject:to:x-sasl-enc:x-sasl-enc; s=smtpout; bh=mg4n9zmNEvdWu6+ obgDVQtVWYB8=; b=L2n6ti4KX4YLdrbqJS95+oauqc+yMeQgzr7Y/ogxx/voeq9 875nkKUWkRDWkLDrjkFoKaib9IoG7sz0iNKLpltbeZeXnkulGBtTKAq8s8CimUTC QbgkuZc3LtdFI79MErBnnjWBzHF4l2wKn3NVrnJD6WxX+A03GMeoLPTk0AYI= X-Sasl-Enc: DEbVp9SnJsSgfy6Py0+9vPYszoU7y3W7pZm5hiBqDj9X 1467129138 X-Mailer: MessagingEngine.com Webmail Interface - ajax-92c7b58a In-Reply-To: X-BeenThere: python-list@python.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: General discussion list for the Python programming language List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Mailman-Original-Message-ID: <1467129138.2539971.650945673.4DB27682@webmail.messagingengine.com> X-Mailman-Original-References: Xref: csiph.com comp.lang.python:110712 On Tue, Jun 28, 2016, at 06:25, Chris Angelico wrote: > For the OP's situation, frankly, I doubt there'll be anything other > than UTF-8, Latin-1, and CP-1252. The chances that someone casually > mixes CP-1252 with (say) CP-1254 would be vanishingly small. So the > simple decode of "UTF-8, or failing that, 1252" is probably going to > give correct results for most of the content. The trick is figuring > out a correct boundary for the check; line-by-line may be sufficient, > or it may not. For completeness, this can be done character-by-character (i.e. try to decode a UTF-8 character, if it fails decode the offending byte as 1252) with an error handler: import codecs def cp1252_errors(exception): input, idx = exception.object, exception.start byte = input[idx:idx+1] try: return byte.decode('windows-1252'), idx+1 except UnicodeDecodeError: # python's cp1252 doesn't accept 0x81, etc return byte.decode('latin1'), idx+1 codecs.register_error('cp1252', cp1252_errors) assert b"t\xe9st\xc3\xadng".decode('utf-8', errors='cp1252') == "t\u00e9st\u00edng" This is probably sufficient for most purposes; byte sequences that happen to be valid UTF-8 characters but mean something sensible in cp-1252 are rare. Just be fortunate that that's all you have to deal with - the equivalent problem for Japanese encodings, for instance, is much harder (you'd probably want the boundary to be "per run of non-ASCII* characters" if lines don't suffice, and detecting the difference between UTF-8, Shift-JIS, and EUC-JP is nontrivial). There's a reason the word "mojibake" comes from Japanese. *well, JIS X 0201, which is ASCII but for 0x5C and 0x7E. And unless you've got ISO-2022 codes to provide context for that, you've just got to guess what those two bytes mean. Fortunately (fsvo), many environments' fonts display the relevant ASCII characters as their JIS alternatives, taking that choice away from you.