Je veux traiter un cas où un bogue de nom de fichier se produit.
Même si le nom de fichier est le même en japonais, il est complètement différent selon que le code de caractère est utf-8 ou shift-jis. Grâce à l'interprétation intelligente de l'interface utilisateur qui affiche le nom du fichier, vous pouvez généralement travailler sans utiliser votre tête, mais si vous devez le faire avec python, le code de caractère est mélangé (le code de caractère diffère selon le fichier à traiter) Situation) devient très gênant. Donc, cette fois, tout en comprenant l'affichage et la conversion de chaque code de caractère, je vise à finalement convertir le nom de fichier japonais de shift-jis en utf-8, qui est la valeur par défaut de python3.
L'hypothèse est de 3 séries. ** 3 séries ** (important car lié au code de caractère). La plupart des connaissances requises pour le code de caractère dans cet article sont ** Site officiel ** (y compris les citations), et certaines Il a été obtenu sur ** ce site **.
J'ai téléchargé l'image de «Sont à mettre sur la plaie» de Irasutoya. Ce nom semble différent selon la région (?). Dans cet article, nous traiterons la relation entre ces noms comme suit.
Le nom «Bansokou» est [Daijirin](https://www.weblio.jp/content/%E3%81%B0%E3%82%93%E3%81%9D%E3%81%86% Il s'agit d'une nomenclature courante publiée dans E3% 81% 93% E3% 81% 86), tandis que "Cut Bang ([Yutoku Yakuhin Kogyo Co., Ltd.](https://www.yutokuyakuhin.co.jp/product/1-" 1.html)) »et« Band Aid (Johnson End Johnson Co., Ltd.) »sont des noms de produits. Je sais qu'il y a des différences de performances et de matériaux selon les sociétés de vente (je ne les ai pas comparées), mais par souci de simplicité, dans cet article, tous ces noms sont les mêmes, «sont à mettre sur la plaie». Supposons que ce soit un mot précis __. En d'autres termes, "celui à attacher à la plaie" est représenté par l'unique <nom (nom du produit) et la notation> selon les quatre types de règles de verbalisation (** code de caractère **) dans la figure. L'application de cette règle de verbalisation pour traduire
Une chaîne Unicode est une chaîne de points de code, qui est un nombre compris entre 0 et 0x10FFFF (1 114 111 en notation décimale). Cette chaîne de points de code est représentée en mémoire sous la forme d'une colonne d'unité de code, qui correspond à une chaîne d'octets de 8 bits. Les règles de traduction d'une chaîne Unicode sous forme de chaîne d'octets sont appelées encodage de caractères ou simplement encodage. (Omis) Le codage par défaut du code source Python est UTF-8, vous pouvez donc inclure des caractères Unicode tels quels dans les littéraux de chaîne.
Dans le code python, le type de chaîne "Doivent être attachés à la plaie" est exprimé en utilisant la ** chaîne de caractères unicode ** (et le ** point de code ** correspondant). Ensuite, lorsque le codage est requis dans le traitement des chaînes de caractères, il est codé comme "bansoko" en utilisant le code de caractère par défaut (hirakana dans l'exemple, UTF-8 en python).
Le code de caractère par défaut peut être confirmé avec le code suivant.
Vérifiez le code de caractère par défaut
import sys
print(sys.getdefaultencoding()) # → utf-8
Inversement, afficher l '
Vous pouvez également utiliser la méthode decode () de la classe> bytes pour créer une chaîne. Cette méthode prend une valeur de type UTF-8 comme argument de codage et éventuellement un argument d'erreurs.
Puisque la correspondance entre <str> .encode ()
et <bytes> .decode ()
peuvent prendre des arguments ʻerreurs`. Le traitement des exceptions est effectué selon les règles spécifiées dans cette variable.
Immédiatement, la chaîne de caractères "Akasatana" est encodée à l'aide de quatre types de codes de caractères.
utf-8 et décalage-Comparaison de jis
str_src = 'Akasa Tana'
enc_utf = str_src.encode() # default: encoding="utf-8"
enc_u16 = str_src.encode('utf-16')
enc_euc = str_src.encode('euc_jp')
enc_jis = str_src.encode('shift-jis')
print('--- ENCODE ---')
print('encoded by utf-8:', enc_utf, '(length={})'.format(len(enc_utf)))
print('encoded by utf-16:', enc_u16, '(length={})'.format(len(enc_u16)))
print('encoded by euc_jp:', enc_euc, '(length={})'.format(len(enc_euc)))
print('encoded by shift-jis:', enc_jis, '(length={})'.format(len(enc_jis)))
print('--- DECODE ---')
print(enc_utf.decode(), enc_u16.decode('utf-16'), enc_euc.decode('euc_jp'), enc_jis.decode('shift-jis'))
'''
--- ENCODE ---
encoded by utf-8: b'\xe3\x81\x82\xe3\x81\x8b\xe3\x81\x95\xe3\x81\x9f\xe3\x81\xaa' (length=15)
encoded by utf-16: b'\xff\xfeB0K0U0_0j0' (length=12)
encoded by euc_jp: b'\xa4\xa2\xa4\xab\xa4\xb5\xa4\xbf\xa4\xca' (length=10)
encoded by shift-jis: b'\x82\xa0\x82\xa9\x82\xb3\x82\xbd\x82\xc8' (length=10)
--- DECODE ---
Akasata Akasata Akasata Akasata
'''
La sortie est tracée comme suit (utf-16 est également affiché en notation hexadécimale).
Les deux octets qui apparaissent au début de l'encodage utilisant utf-16 sont un code appelé BOM.
Le caractère Unicode U + FEFF est utilisé comme marque d'ordre des octets (BOM) et est écrit comme premier caractère du fichier pour aider à la détermination automatique de l'ordre des octets du fichier. Certains encodages, comme UTF-16, nécessitent une nomenclature au début du fichier; lorsqu'un tel encodage est utilisé, la nomenclature est automatiquement écrite comme premier caractère et lors de la lecture du fichier Est implicitement supprimé.
Pensez maintenant à créer un fichier en spécifiant le nom du fichier dans le code python. Comme d'habitude, on réfléchit au principe en "le collant sur la plaie". Pour réitérer, ** Ici, nous allons nous concentrer sur le "nom du fichier" et poursuivre la discussion sans trop nous soucier du contenu du fichier créé **.
Lors de la fabrication de "Doivent être attachés à une plaie", le nom "Appel" est enregistré sur le disque. Ensuite, quand «cela» est nécessaire, il sera traduit (décodé) à chaque fois de «l'appel» à «celui à attacher à la plaie» dans le cerveau de la règle de verbalisation attendue.
Considérons ici le cas où la règle de verbalisation attendue n'est que celle de Yutoku Yakuhin. Si le
Si vous travaillez sans penser à rien, le code de caractère d'encodage spécifié par défaut dans python3 sera appliqué au nom du fichier lors de la génération du fichier. En outre, la valeur par défaut de l'argument «erreurs» est également déterminée. Ceux-ci peuvent également être confirmés par le code suivant.
python
import sys
print(sys.getfilesystemencoding())
print(sys.getfilesystemencodeerrors())
'''
utf-8
surrogateescape
'''
«Surrogate» lui-même a été nouvellement introduit en tant que code pour étendre davantage la zone d'expression d'Unicode. Dans ʻerrors = surrogate escape au moment du décodage de type octets de Python3, la partie correspondante des octets qui ne peut pas être décodée est remplacée par la chaîne de caractères unicode utilisée dans le surrogate. En conséquence, bien que le décodage lui-même soit incomplet, des erreurs peuvent être évitées sans perdre les informations de type d'octets d'origine. Lorsque vous souhaitez recoder le même code, la chaîne de caractères Unicode insérée en spécifiant ʻerrors = substitate escape
est supprimée afin que le formulaire d'origine puisse être restauré.
Le gestionnaire d'erreurs de substitution décode tous les octets non ASCII en tant que points de code dans la zone privée Unicode de U + DC80 à U + DCFF. Ces points de code privés sont renvoyés aux mêmes octets lors de l'utilisation de surrogateescape, un gestionnaire d'erreurs lors du codage et de la réécriture des données.
Maintenant, envisagez de sauvegarder le fichier avec le nom japonais comme utf-8 et shift-jis, en faisant attention à ce qui précède.
Importez le module à utiliser et créez un répertoire de travail. Cet article n'utilise pas de modules de traitement de code de caractères tels que les codecs (je ne suis pas sûr).
Préparation: Importez le module utilisé, créez un répertoire de travail
import os
import glob
testdir = './testdir'
if not os.path.exists(testdir):
os.mkdir(testdir)
#Rechercher et afficher le chemin du répertoire courant, en se limitant au répertoire
print([p for p in glob.glob('./*') if os.path.isdir(p)])
'''
[..., './testdir', ...]
'''
Comme mentionné ci-dessus, lorsque le code de caractère est utf-8, il est spécifié comme valeur par défaut de python3, il n'y a donc rien à faire attention.
Utilisez ʻos.mkdir () `pour créer le répertoire utf-8" Aiueo "dans le répertoire de travail.
Créer un répertoire (utf-8)
utf_dirname = os.path.join(testdir, 'AIUEO')
os.mkdir(utf_dirname)
De plus, créez "Kakikukeko.txt" dans "Aiueo". Bien qu'elle ne soit pas utilisée dans cet article, la chaîne de caractères par utf-8 est sortie dans le fichier.
Création de fichier (utf-8)
utf_filename = os.path.join(utf_dirname, 'Kakikukeko.txt')
with open(utf_filename, 'w') as f:
f.write('SA Shi Su Se So\n')
Enfin, créez un nouveau fichier dont le nom de fichier est défini par shift-jis.
Créez un répertoire shift-jis "Akasatana" dans le répertoire de travail. Jusqu'à présent, le type str était donné à ʻos.mkdir () `, mais cela fonctionne normalement même si ** type bytes est inséré **.
python
jis_dirname = os.path.join(testdir, 'Akasa Tana').encode('shift-jis')
print(jis_dirname)
os.mkdir(jis_dirname)
'''
b'./testdir/\x82\xa0\x82\xa9\x82\xb3\x82\xbd\x82\xc8'
'''
Plus tôt, nous avons montré qu'un nouveau répertoire peut être créé en utilisant le nom de chemin de type bytes, mais cette fois nous allons créer le répertoire shift-jis "Akasatana" en utilisant le type str.
Comme mentionné ci-dessus, il est connu que ʻencoding = 'utf-8' et ʻerrors =' surrogate escape'
sont utilisés lors de l'encodage du nom de fichier par défaut, utilisez donc ces options pour changer le type d'octets en type str. Convertir (décoder) en. En spécifiant «erreurs», «dc» est ajouté au début de chaque chaîne de caractères Unicode en sortie.
Lorsque la chaîne de caractères unicode de type str générée est placée dans print ()
par ce décodage spécial, une erreur (ʻUnicodeDecodeError) est renvoyée. Par conséquent, en l'enfermant dans
repr ()`, la chaîne de caractères unicode est sortie telle quelle.
Créer un répertoire (shift-jis)
jis_dirname_bytes = os.path.join(testdir, 'Akasa Tana'.encode('shift-jis')
jis_dirname_str = jis_dirname_bytes.decode(errors='surrogateescape'))
print(repr(jis_dirname_str))
os.mkdir(jis_dirname_str)
'''
'./testdir/\udc82\udca0\udc82\udca9\udc82\udcb3\udc82\udcbd\udc82\udcc8'
'''
Créez "Hamayarawa.txt" dans le répertoire "Akasatana" avec shift-jis. Le code de caractère du texte du fichier est également défini sur shift-jis par ʻencoding = 'shift-jis'`.
Création de fichier (shift-jis)
jis_filename = os.path.join(jis_dirname, 'Hamayarawa.txt'.encode('shift-jis'))
# encode()Après.decode(errors='surrogateescape')Peut être joint
with open(jis_filename, 'w', encoding='shift-jis') as f:
f.write('Tout à coup\n Himiri')
Jusqu'à présent, nous avons défini le nom du fichier avec deux types de codes de caractères, mais affichons-le avec l'interface utilisateur et glob.glob ()
. Dans la figure ci-dessous, le carré bleu au milieu est le nom du fichier enregistré (octets). Le côté inférieur montre le résultat de l'interface utilisateur traduisant le nom du fichier en spécifiant le code de caractère, et le côté supérieur montre le résultat de l'obtention de la liste des noms de fichier en type str ou en type octets en python.
J'ai utilisé la première page de Jupyter Notebook. Bien que le répertoire "aiueo" créé par utf-8 soit affiché normalement. Le répertoire "Akasatana" créé par shift-jis est déformé et ne peut pas être sélectionné.
"Kakikukeko.txt" dans le répertoire "Aiueo" est également affiché sans aucun problème.
J'ai utilisé WinSCP. Bien que le répertoire "Akasatana" créé par shift-jis s'affiche normalement. Le répertoire "aiueo" créé par utf-8 est déformé, et une erreur se produira s'il est sélectionné.
"Hamayarawa.txt" dans le répertoire "Akasatana" est également affiché sans aucun problème.
glob.glob ()
Si vous essayez d'obtenir une liste de fichiers dans le répertoire de travail normalement, le nom du fichier sera décodé par l'utf-8 par défaut, donc le répertoire ** "Akasatana" sera de type str avec surrogate escape
**.
utf-8 pour afficher le nom du chemin
print(glob.glob(os.path.join(testdir, '*')))
print(glob.glob(os.path.join(testdir, 'AIUEO', '*')))
'''
['./testdir/AIUEO',
'./testdir/\udc82\udca0\udc82\udca9\udc82\udcb3\udc82\udcbd\udc82\udcc8']
['./testdir/AIUEO/Kakikukeko.txt']
'''
Ici, le type d'octets est attribué à ** glob.glob ()
, et le nom de fichier est acquis par la ** méthode de décodage de la sortie obtenue avec un code arbitraire.
Si vous décodez avec shift-jis, le nom du répertoire "Akasatana" sera affiché normalement, et le répertoire "Aiueo" sera brouillé.
Liste des noms de chemins utilisant des octets
#Obtenir le nom du fichier avec le type d'octets
bytes_paths = glob.glob(os.path.join(testdir, '*').encode())
print(bytes_paths)
# utf-Décoder à 8
print([f.decode(errors='surrogateescape') for f in bytes_paths])
# shift-Décoder avec jis
print([f.decode('shift-jis', errors='surrogateescape') for f in bytes_paths])
'''
[b'./testdir/\xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88\xe3\x81\x8a',
b'./testdir/\x82\xa0\x82\xa9\x82\xb3\x82\xbd\x82\xc8']
['./testdir/AIUEO',
'./testdir/\udc82\udca0\udc82\udca9\udc82\udcb3\udc82\udcbd\udc82\udcc8']
['./testdir/縺 > 縺\udc86 Docteur ♀',
'./testdir/Akasa Tana']
'''
Enfin, remplacez le nom de fichier enregistré par shift-jis par le nom de fichier défini par utf-8.
Récupérez directement le chemin du répertoire défini par shift-jis et remplacez-le par la chaîne de utf-8 par ʻos.rename () `.
Conversion de code de caractère de répertoire unique
target = glob.glob(os.path.join(testdir, '*').encode())[1]
print(repr(target))
print(target.decode('shift-jis'))
os.rename(target, target.decode('shift-jis'))
'''
b'./testdir/\x82\xa0\x82\xa9\x82\xb3\x82\xbd\x82\xc8'
./testdir/Akasa Tana
'''
Le résultat est présenté ci-dessous. Le code du caractère a été converti avec succès et "Akasatana" est visible.
Entrez dans le répertoire "Akasatana".
Dans cet article, il n'existe qu'un seul fichier, mais en supposant le cas où la conversion de code de caractère de plusieurs fichiers est requise, le code avec traitement en boucle est utilisé. En se concentrant sur la partie japonaise, la partie "Akasatana" est la chaîne de caractères utf-8, et le "Hamayarawa.txt" est la chaîne de caractères shift-jis. ** Ce sont des décodages de type mixte et octets Renvoie une erreur ** (Puisque la partie "./testdir" est incluse dans la chaîne de caractères ascii, utf-8 et shift-jis fonctionnent avec des octets communs, vous n'avez donc pas à y penser). Il est nécessaire de séparer ces deux avant le traitement.
Conversion de code de caractère de tous les fichiers du répertoire
for f in glob.glob(os.path.join(testdir, 'Akasa Tana', '*').encode()):
#Nom du répertoire (utf-Décoder avec 8)
d_str = os.path.dirname(f).decode()
#Nom de fichier (shift-Décoder avec jis)
b_str = os.path.basename(f).decode('shift-jis')
#Conversion de code de caractère
os.rename(f, os.path.join(d_str, b_str))
Avec cela, "Hamayarawa.txt" a également été défini en toute sécurité avec le code de caractère de utf-8.
Jusqu'à présent, je pense avoir enfin compris le talent pour manipuler les chaînes de caractères. En particulier, j'ai trouvé que le travail devient beaucoup plus facile si je fais bon usage du type bytes, auquel j'étais habitué et dont je ne me souciais pas du tout. En plus de cela, si vous pouvez choisir la gestion des «erreurs» au moment de l'encodage / décodage, la plupart du travail sera possible.
Après tout, je pense que le document officiel est le plus simple à comprendre.
Recommended Posts