Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Making Acquaintances with Exotic Encodings

Making Acquaintances with Exotic Encodings

Text encoding is a relatively straightforward feature of Python at first glance, but in the wild there are a lot of strange cases we can encounter.

Avatar for Trapsilo Bumi

Trapsilo Bumi

August 03, 2019

More Decks by Trapsilo Bumi

Other Decks in Programming

Transcript

  1. About Me Trapsilo Pramudya Bumi From Bandung, Indonesia Software Engineer

    at HENNGE K.K. Shibuya, Tokyo, Japan B2B cloud security solutions hennge.com/global/about
  2. US-ASCII was one of the first successful standardized “mappings” Different

    standards were created by different people around the world Many were extending ASCII in different ways This created “bilingual encodings”, but not “multilingual” The Unicode Standard was created to unify them
  3. Unicode concept: code-points Assigns a number, not a glyph, to

    a “character” or “grapheme” Leaves the visual rendering to software Independent of the code unit (bit sequence)
  4. Character Glyph Unicode Code Point Code Units in UTF-8 Code

    Units in UTF-32 LATIN SMALL LETTER A a a U+0061 0x61 0x00000061 LATIN SMALL LETTER SHARP S ß U+00DF 0xDF 0x000000DF HAN FOR EAST 東 U+6771 0x67 0x71 0x00006771 DESERET CAPITAL LETTER LONG I U+10400 0xF0 0x90 0x90 0x80 0x00010400
  5. Encoding in Python Text Sequence a.k.a “Unicode strings” Binary Sequence

    a.k.a “Byte strings” Sequence of Unicode code points Sequence of single bytes
  6. Encoding in Python (2) Converting one to another: decode() and

    encode() bytes.decode(encoding, errors) -> str str.encode(encoding, errors) -> bytes First parameter: encoding (how to translate from code point to bytes/reverse) Second parameter: errors (how to handle unrecognized code points)
  7. Non-Unicode text as the standard: Emails RFC 821 (SMTP protocol)

    dictates the use of ASCII Using non-ASCII characters requires SMTP extensions/MIME (RFC 5321) Many email clients don’t provide Unicode as the default
  8. Latin-1 a.k.a ISO-8859-1 a.k.a CP819 The basis for most popular

    8-bit character sets The default encoding for documents that are delivered via HTTP MIME type “text/*”
  9. Windows-1252 a.k.a CP-1252 Used by default in the legacy components

    for Windows Windows → Microsoft Office → popular!
  10. GB18030 The official character set for the People’s Republic of

    China “Unicode Transformation Format” Superseding GB2312
  11. Big5 A popular encoding in Taiwan, Hong Kong, and Macau

    1980s standard, before Unicode China used this before creating the GB* standard Extended by lots of organizations E.g. Microsoft Code Page 950
  12. Shift JIS Developed by “ASCII Corporation” and Microsoft One of

    the prominent Japanese character encodings
  13. The codecs package Simply, using encode() and decode() to switch

    between bytes ⇔ str Defaults to UTF-8, can specify alternative encoding errors parameter specifies how to handle unrecognized code points: ignore - skip the code point strict - raise an Exception replace - replace the unknown code point with something, e.g. �
  14. But what if... We don’t know the encoding for this

    text? There is a specified encoding, but it doesn’t match/work/spits out mojibake? There is just no way to specify the encoding in that document/file/whatever? It happens a lot: Scraping websites Reading/parsing email
  15. Enter… chardet Character encoding auto-detection library How it works: heuristics

    to map common patterns to a specific language Based on universalchardet by Mozilla
  16. So, is chardet the answer to everything? No, use it

    as a last resort when: It’s HTTP and there is no charset parameter in the Content-Type header It’s HTML and there is no <meta http-equiv="content-type"> It’s XML and there is no encoding attribute in the prolog It’s something else and there is no explicit character encoding
  17. chardet is not perfect It can spit out EUC-TW: not

    in Python’s standard library! It has a confidence rating that is sometimes very low Set a threshold according to your tolerance
  18. The last, last resort Using a static table that is

    based on experience: PYCODECNAMES = { 'cp943' : 'cp932', 'cp943c' : 'cp932', 'cswindows31j': 'cp932', 'ibm-943' : 'cp932', 'ibm-943c' : 'cp932', 'ja16sjis' : 'cp932', 'macjapan' : 'cp932', }
  19. Especially for MIME messages, encodings aren’t always written one way.

    { 'cp65001' : 'utf_8', 'en_gb' : 'utf_8', 'utf-8-hfs' : 'utf_8', 'utf-8-mac' : 'utf_8', 'utf8-docomo' : 'utf_8', 'utf8-kddi' : 'utf_8', 'utf8-mac' : 'utf_8', 'utf8-softbank' : 'utf_8', }
  20. Encoding is important to understand Useful for text processing Keep

    some tricks up the sleeve for handling exotic character mappings chardet package Static list of aliases