2016-09-20 2 views
2

Frage

Warum ist die gleiche Zeichencodierung für verschiedene Bytes in verschiedenen Teilen meiner Codebasis?Warum codiert 'é' und 'é' für verschiedene Bytes?

Kontext

Ich habe einen Unit-Test, die einen temporären Dateibaum erzeugt und prüfen dann, meine Scan findet die Datei tatsächlich in Frage stellen Sie sicher.

def test_unicode_file_name(): 
    test_regex = "é" 
    file_tree = {"files": ["é"]} # File created with python.open() 
    with TempTree(file_tree) as tmp_tree: 
     import pdb; pdb.set_trace() 
     result = tasks.find_files(test_regex, root_path=tmp_tree.root_path) 
     expected = [os.path.join(tmp_tree.root_path, "é")] 
     assert result == expected 

Funktion, die zu verschiedenen

for dir_entry in scandir(current_path): 
    if dir_entry.is_dir(): 
     dirs_to_search.append(dir_entry.path) 

    if dir_entry.is_file(): 
     testing = dir_entry.name 
     if filename_regex.match(testing): 
      results.append(dir_entry.path) 

PDB Session

Als ich Grabe in Dinge begann, fand ich, dass das Test-Zeichen (kopiert von meinem Unit-Test) und das Zeichen in dir_entry.name codiert ist versagt Bytes.

(Pdb) testing 
'é' 
(Pdb) 'é' 
'é' 
(Pdb) testing == 'é' 
False 
(Pdb) testing in 'é' 
False 
(Pdb) type(testing) 
<class 'str'> 
(Pdb) type('é') 
<class 'str'> 
(Pdb) repr(testing) 
"'é'" 
(Pdb) repr('é') 
"'é'" 
(Pdb) 'é'.encode("utf-8") 
b'\xc3\xa9' 
(Pdb) testing.encode("utf-8") 
b'e\xcc\x81' 

Antwort

3

Ihr Betriebssystem (MacOS, bei einer guess) hat den Dateinamen zu 'é'Unicode Normal Form D umgewandelt, in eine tonloses 'e' und einer Kombination von Akut zersetzen. Sie können dies eindeutig mit einer schnellen Sitzung im Interpreter Python sehen:

>>> import unicodedata 
>>> e1 = b'\xc3\xa9'.decode() 
>>> e2 = b'e\xcc\x81'.decode() 
>>> [unicodedata.name(c) for c in e1] 
['LATIN SMALL LETTER E WITH ACUTE'] 
>>> [unicodedata.name(c) for c in e2] 
['LATIN SMALL LETTER E', 'COMBINING ACUTE ACCENT'] 

Um sicherzustellen, dass Sie Gleiches mit Gleichem sind zu vergleichen, können Sie die Dateinamen von dir_entry.name zurück in Normalform C gegeben konvertieren, bevor die Prüfung gegen Ihre Regex:

import unicodedata 

for dir_entry in scandir(current_path): 
    if dir_entry.is_dir(): 
     dirs_to_search.append(dir_entry.path) 

    if dir_entry.is_file(): 
     testing = unicodedata.normalize('NFC', dir_entry.name) 
     if filename_regex.match(testing): 
      results.append(dir_entry.path) 
+0

Warum verwenden 'NFC' anstelle von' NFD'? Spielt es eine Rolle, in welchem ​​normalisierten Format Sie arbeiten? – AlexLordThorsen

+0

Korrigieren Sie auch das Betriebssystem. – AlexLordThorsen

+2

NFC ist kompakter und ist die Form, die (skurrile Dateisystem Entscheidungen von Apple beiseite) Sie am häufigsten finden - zum Beispiel ist es offensichtlich, was Sie bekommen, wenn Sie 'é' in Ihren Editor getippt haben. Es ist auch die Form [von W3C empfohlen] (https://www.w3.org/TR/charmod-norm/#choice-of-normalization-form), für was auch immer es sich lohnt. –

Verwandte Themen