<div dir="ltr"><div><div><div>I'm looking at the documentation of "best fit" mappings, and that seems to be a different matter. It appears that best-fit mappings are designed to be many-to-one mappings used only for encoding.<br><br>"Examples of best fit are converting fullwidth letters to their counterparts when converting to single byte code pages, and mapping the Infinity character to the number 8." (Mapping ∞ to 8? Seriously?!) It also does things such as mapping Cyrillic letters to Latin letters that look like them.<br></div></div><br></div>This is not what I'm interested in implementing. I just want there to be encodings that match the WHATWG encodings exactly. If they have to be given a different name, that's fine with me.<br></div><br><div class="gmail_quote"><div dir="ltr">On Wed, 10 Jan 2018 at 03:38 M.-A. Lemburg <<a href="mailto:mal@egenix.com">mal@egenix.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On 10.01.2018 00:56, Rob Speer wrote:<br>
> Oh that's interesting. So it seems to be Python that's the exception here.<br>
><br>
> Would we really be able to add entries to character mappings that haven't<br>
> changed since Python 2.0?<br>
<br>
The Windows mappings in Python come directly from the Unicode<br>
Consortium mapping files.<br>
<br>
If the Consortium changes the mappings, we can update them.<br>
<br>
If not, then we have a problem, since consumers are not only<br>
the win32 APIs, but also other tools out there running on<br>
completely different platforms, e.g. Java tools or web servers<br>
providing downloads using the Windows code page encodings.<br>
<br>
Allowing such mappings in the existing codecs would then result<br>
failures when the "other" sides see the decoded Unicode version and<br>
try to encode back into the original encoding - you'd move the<br>
problem from the Python side to the "other" side of the<br>
integration.<br>
<br>
I had a look on the Unicode FTP site and they have since added<br>
a new directory with mapping files they call "best fit":<br>
<br>
<a href="http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WindowsBestFit/readme.txt" rel="noreferrer" target="_blank">http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WindowsBestFit/readme.txt</a><br>
<br>
The WideCharToMultiByte() defaults to best fit, but also offers<br>
a mode where it operates in standards compliant mode:<br>
<br>
<a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd374130%28v=vs.85%29.aspx" rel="noreferrer" target="_blank">https://msdn.microsoft.com/en-us/library/windows/desktop/dd374130%28v=vs.85%29.aspx</a><br>
<br>
See flag WC_NO_BEST_FIT_CHARS.<br>
<br>
Unicode TR#22 is also clear on this:<br>
<br>
<a href="https://www.unicode.org/reports/tr22/tr22-3.html#Illegal_and_Unassigned" rel="noreferrer" target="_blank">https://www.unicode.org/reports/tr22/tr22-3.html#Illegal_and_Unassigned</a><br>
<br>
It allows such best fit mappings to make encodings round-trip<br>
safe, but requires to keep these separate from the original<br>
standard mappings:<br>
<br>
"""<br>
It is very important that systems be able to distinguish between the<br>
fallback mappings and regular mappings. Systems like XML require the use<br>
of hex escape sequences (NCRs) to preserve round-trip integrity; use of<br>
fallback characters in that case corrupts the data.<br>
"""<br>
<br>
If you read the above section in TR#22 you quickly get reminded<br>
of what the Unicode error handlers do (we basically implement<br>
the three modes it mentions... raise, ignore, replace).<br>
<br>
Now, for unmapped sequences an error handler can opt for<br>
using a fallback sequence instead.<br>
<br>
So in addition to adding best fit codecs, there's also the<br>
option to add an error handler for best fit resolution of<br>
unmapped sequences.<br>
<br>
Given the above, I don't think we ought to change the existing<br>
standards compliant mappings, but use one of two solutions:<br>
<br>
a) add "best fit" encodings (see the Unicode FTP site for<br>
   a list)<br>
<br>
b) add an error handlers "bestfit" which implements the<br>
   fallback modes for the encodings in question<br>
<br>
<br>
> On Tue, 9 Jan 2018 at 16:53 Ivan Pozdeev via Python-ideas <<br>
> <a href="mailto:python-ideas@python.org" target="_blank">python-ideas@python.org</a>> wrote:<br>
><br>
>> First of all, many thanks for such a excellently writen letter. It was a<br>
>> real pleasure to read.<br>
>> On 10.01.2018 0:15, Rob Speer wrote:<br>
>><br>
>> Hi! I joined this list because I'm interested in filling a gap in Python's<br>
>> standard library, relating to text encodings.<br>
>><br>
>> There is an encoding with no name of its own. It's supported by every<br>
>> current web browser and standardized by WHATWG. It's so prevalent that if<br>
>> you ask a Web browser to decode "iso-8859-1" or "windows-1252", you will<br>
>> get this encoding _instead_. It is probably the second or third most common<br>
>> text encoding in the world. And Python doesn't quite support it.<br>
>><br>
>> You can see the character table for this encoding at:<br>
>> <a href="https://encoding.spec.whatwg.org/index-windows-1252.txt" rel="noreferrer" target="_blank">https://encoding.spec.whatwg.org/index-windows-1252.txt</a><br>
>><br>
>> For the sake of discussion, let's call this encoding "web-1252". WHATWG<br>
>> calls it "windows-1252", but notice that it's subtly different from<br>
>> Python's "windows-1252" encoding. Python's windows-1252 has bytes that are<br>
>> undefined:<br>
>><br>
>>>>> b'\x90'.decode('windows-1252')<br>
>> UnicodeDecodeError: 'charmap' codec can't decode byte 0x90 in position 0:<br>
>> character maps to <undefined><br>
>><br>
>> In web-1252, the bytes that are undefined according to windows-1252 map to<br>
>> the control characters in those positions in iso-8859-1 -- that is, the<br>
>> Unicode codepoints with the same number as the byte. In web-1252, b'\x90'<br>
>> would decode as '\u0090'.<br>
>><br>
>> According to <a href="https://en.wikipedia.org/wiki/Windows-1252" rel="noreferrer" target="_blank">https://en.wikipedia.org/wiki/Windows-1252</a> , Windows does<br>
>> the same:<br>
>><br>
>>     "According to the information on Microsoft's and the Unicode<br>
>> Consortium's websites, positions 81, 8D, 8F, 90, and 9D are unused;<br>
>> however, the Windows API MultiByteToWideChar<br>
>> <<a href="http://msdn.microsoft.com/en-us/library/windows/desktop/dd319072%28v=vs.85%29.aspx" rel="noreferrer" target="_blank">http://msdn.microsoft.com/en-us/library/windows/desktop/dd319072%28v=vs.85%29.aspx</a>><br>
>> maps these to the corresponding C1 control codes<br>
>> <<a href="https://en.wikipedia.org/wiki/C0_and_C1_control_codes" rel="noreferrer" target="_blank">https://en.wikipedia.org/wiki/C0_and_C1_control_codes</a>>."<br>
>> And in ISO-8859-1, the same handling is done for unused code points even<br>
>> by the standard ( <a href="https://en.wikipedia.org/wiki/ISO/IEC_8859-1" rel="noreferrer" target="_blank">https://en.wikipedia.org/wiki/ISO/IEC_8859-1</a> ) :<br>
>><br>
>>     "*ISO-8859-1* is the IANA<br>
>> <<a href="https://en.wikipedia.org/wiki/Internet_Assigned_Numbers_Authority" rel="noreferrer" target="_blank">https://en.wikipedia.org/wiki/Internet_Assigned_Numbers_Authority</a>><br>
>> preferred name for this standard when supplemented with the C0 and C1<br>
>> control codes <<a href="https://en.wikipedia.org/wiki/C0_and_C1_control_codes" rel="noreferrer" target="_blank">https://en.wikipedia.org/wiki/C0_and_C1_control_codes</a>><br>
>> from ISO/IEC 6429 <<a href="https://en.wikipedia.org/wiki/ISO/IEC_6429" rel="noreferrer" target="_blank">https://en.wikipedia.org/wiki/ISO/IEC_6429</a>>"<br>
>> And what would you think -- these "C1 control codes" are also the<br>
>> corresponding Unicode points! (<br>
>> <a href="https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)" rel="noreferrer" target="_blank">https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)</a> )<br>
>><br>
>> Since Windows is pretty much the reference implementation for<br>
>> "windows-xxxx" encodings, it even makes sense to alter the existing<br>
>> encodings rather than add new ones.<br>
>><br>
>><br>
>> This may seem like a silly encoding that encourages doing horrible things<br>
>> with text. That's pretty much the case. But there's a reason every Web<br>
>> browser implements it:<br>
>><br>
>> - It's compatible with windows-1252<br>
>> - Any sequence of bytes can be round-tripped through it without losing<br>
>> information<br>
>><br>
>> It's not just this one encoding. WHATWG's encoding standard (<br>
>> <a href="https://encoding.spec.whatwg.org/" rel="noreferrer" target="_blank">https://encoding.spec.whatwg.org/</a>) contains modified versions of<br>
>> windows-1250 through windows-1258 and windows-874.<br>
>><br>
>> Support for these encodings matters to me, in part, because I maintain a<br>
>> Unicode data-cleaning library, "ftfy". One thing it does is to detect and<br>
>> undo encoding/decoding errors that cause mojibake, as long as they're<br>
>> detectible and reversible. Looking at real-world examples of text that has<br>
>> been damaged by mojibake, it's clear that lots of text is transferred<br>
>> through what I'm calling the "web-1252" encoding, in a way that's<br>
>> incompatible with Python's "windows-1252".<br>
>><br>
>> In order to be able to work with and fix this kind of text, ftfy registers<br>
>> new codecs -- and I implemented this even before I knew that they were<br>
>> standardized in Web browsers. When ftfy is imported, you can decode text as<br>
>> "sloppy-windows-1252" (the name I chose for this encoding), for example.<br>
>><br>
>> ftfy can tell people a sequence of steps that they can use in the future<br>
>> to fix text that's like the text they provided. Very often, these steps<br>
>> require the sloppy-windows-1252 or sloppy-windows-1251 encoding, which<br>
>> means the steps only work with ftfy imported, even for people who are not<br>
>> using the features of ftfy.<br>
>><br>
>> Support for these encodings also seems highly relevant to people who use<br>
>> Python for web scraping, as it would be desirable to maximize compatibility<br>
>> with what a Web browser would do.<br>
>><br>
>> This really seems like it belongs in the standard library instead of being<br>
>> an incidental feature of my library. I know that code in the standard<br>
>> library has "one foot in the grave". I _want_ these legacy encodings to<br>
>> have one foot in the grave. But some of them are extremely common, and<br>
>> Python code should be able to deal with them.<br>
>><br>
>> Adding these encodings to Python would be straightforward to implement.<br>
>> Does this require a PEP, a pull request, or further discussion?<br>
>><br>
>><br>
>> _______________________________________________<br>
>> Python-ideas mailing listPython-ideas@python.orghttps://<a href="http://mail.python.org/mailman/listinfo/python-ideas" rel="noreferrer" target="_blank">mail.python.org/mailman/listinfo/python-ideas</a><br>
>> Code of Conduct: <a href="http://python.org/psf/codeofconduct/" rel="noreferrer" target="_blank">http://python.org/psf/codeofconduct/</a><br>
>><br>
>><br>
>> --<br>
>> Regards,<br>
>> Ivan<br>
>><br>
>> _______________________________________________<br>
>> Python-ideas mailing list<br>
>> <a href="mailto:Python-ideas@python.org" target="_blank">Python-ideas@python.org</a><br>
>> <a href="https://mail.python.org/mailman/listinfo/python-ideas" rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/python-ideas</a><br>
>> Code of Conduct: <a href="http://python.org/psf/codeofconduct/" rel="noreferrer" target="_blank">http://python.org/psf/codeofconduct/</a><br>
>><br>
><br>
><br>
><br>
> _______________________________________________<br>
> Python-ideas mailing list<br>
> <a href="mailto:Python-ideas@python.org" target="_blank">Python-ideas@python.org</a><br>
> <a href="https://mail.python.org/mailman/listinfo/python-ideas" rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/python-ideas</a><br>
> Code of Conduct: <a href="http://python.org/psf/codeofconduct/" rel="noreferrer" target="_blank">http://python.org/psf/codeofconduct/</a><br>
><br>
<br>
--<br>
Marc-Andre Lemburg<br>
eGenix.com<br>
<br>
Professional Python Services directly from the Experts (#1, Jan 10 2018)<br>
>>> Python Projects, Coaching and Consulting ...  <a href="http://www.egenix.com/" rel="noreferrer" target="_blank">http://www.egenix.com/</a><br>
>>> Python Database Interfaces ...           <a href="http://products.egenix.com/" rel="noreferrer" target="_blank">http://products.egenix.com/</a><br>
>>> Plone/Zope Database Interfaces ...           <a href="http://zope.egenix.com/" rel="noreferrer" target="_blank">http://zope.egenix.com/</a><br>
________________________________________________________________________<br>
<br>
::: We implement business ideas - efficiently in both time and costs :::<br>
<br>
   eGenix.com Software, Skills and Services GmbH  Pastor-Loeh-Str.48<br>
    D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg<br>
           Registered at Amtsgericht Duesseldorf: HRB 46611<br>
               <a href="http://www.egenix.com/company/contact/" rel="noreferrer" target="_blank">http://www.egenix.com/company/contact/</a><br>
                      <a href="http://www.malemburg.com/" rel="noreferrer" target="_blank">http://www.malemburg.com/</a><br>
</blockquote></div>