5
votes

UnicodeEncodeError: le codec 'latin-1' ne peut pas encoder le caractère '\ u2013' (écriture au format PDF)

Je rencontre un problème avec Unicode avec un contenu variable lors de l'écriture dans un .pdf avec python.

Il génère cette erreur:

XXX

Ce qui se fait prendre sur un tiret em en gros.

J'ai essayé de prendre cette variable, où le contenu a un «em dash» et de la redéfinir avec un « .encode (« utf-8 ») » par exemple, ie , ci-dessous:

from fpdf import FPDF
import win32com.client

outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
msg = outlook.OpenSharedItem(r"C:\User\language\python\Msg-To-PDF\test_msg.msg")

print (msg.SenderName)
print (msg.SenderEmailAddress)
print (msg.SentOn)
print (msg.To)
print (msg.CC)
print (msg.BCC)
print (msg.Subject)
print (msg.Body)

SenderName = msg.SenderName
SenderEmailAddress = msg.SenderEmailAddress
SentOn = msg.SentOn
To = msg.To
CC = msg.CC
BCC = msg.BCC
Subject = msg.Subject
Body = msg.Body
BodyC = Body.encode('utf-8')

pdf = FPDF()
pdf.add_page()

# pdf.add_font('DejaVu', '', 'DejaVuSansCondensed.ttf', uni=True)
pdf.set_font("Helvetica", style = '', size = 11)
pdf.cell(200, 10, txt="From: " + SenderName, ln=1, align="C")
# pdf.cell(200, 10, border=SentOn, ln=1, align="C")
pdf.cell(200, 10, txt="To: " + To, ln=1, align="C")
pdf.cell(200, 10, txt="CC: " + CC, ln=1, align="C")
pdf.cell(200, 10, txt="BCC: " + BCC, ln=1, align="C")
pdf.cell(200, 10, txt="Subject: " + Subject, ln=1, align="C")
pdf.cell(200, 10, txt="Bod: " + BodyC,  ln=4, align="C")

pdf.output("Sample.pdf")

Et maintenant, j'obtiens l'erreur ci-dessous:

Traceback (most recent call last):
  File "script.py", line 37, in <module>
    pdf.cell(200, 10, txt="Bod: " + BodyC,  ln=4, align="C")
TypeError: can only concatenate str (not "bytes") to str

Ci-dessous mon code complet, comment pourrais-je simplement corriger mon erreur Unicode dans le contenu de la variable ' Body '.

Conversion en utf-8 ou western , tout ce qui est en dehors de ' latin-1 '. Des suggestions?

Code complet:

Body = msg.Body

BodyC = Body.encode('utf-8')
  • Comment puis-je changer de 'latin1'?^

  • Quoi qu'il en soit, pour résoudre ces problèmes de manière globale?


12 commentaires

Avez-vous essayé de diffuser le msg.Body avec str (msg.Body) ?


Où, que voulez-vous dire?


Body = massage.Body -> Body = str (msg.Body) ?


Il produit toujours exactement la même erreur 'UnicodeEncodeError: le codec' latin-1 'ne peut pas encoder le caractère' \ u2013 'en position 485: ordinal pas dans la plage (256)'


Essayez cette réponse: stackoverflow.com/questions/6539881/...


BodyC = Body.encode ('utf-8') ne fait rien! Un autre point est la sortie d'erreur \ u2013 est unicode mais l'encodage à l'échelle du système n'est pas correctement défini. Quelques avertissements: User_class quel sous-processus appelle avec l'encodage par défaut? la plupart des erreurs de codage sont générées par des fichiers / objets d'E / S non RAW. @ladygremlin whindows toujours à l'exception de ces erreurs, j'ai résolu l'encodage à l'échelle du système par UTF-8 (pas Unicode).


@dsgdfg Ahhh, je ne savais pas que Windows lançait toujours ça. Ce n'est pas mon système d'exploitation de choix. :)


sur python idle '\ x64 \ x45' + 'teest' = 'dEteest' signifie que j'ai utilisé python2.7.X donc si vous utilisez python3.x convertit les octets en chaîne avec le codage source.


@dsgdfg Des suggestions?


Copie possible de Python: UnicodeEncodeError: le codec 'latin-1' ne peut pas encoder le caractère


UnicodeEncodeError: le codec 'latin-1' ne peut pas encoder le caractère


@phuclv donc j'ai corrigé cette erreur spécifique; mais comment puis-je gérer globalement ces problèmes?


3 Réponses :


9
votes

Une solution de contournement consiste à convertir tout le texte en encodage latin-1 avant de le transmettre à la bibliothèque. Vous pouvez le faire avec la commande suivante:

text2 = text.encode('latin-1', 'replace').decode('latin-1')

text2 sera libre de tout caractère non latin-1. Cependant, certains caractères peuvent être remplacés par ?


3 commentaires

fait ce travail dans Python 3 ... J'ai des problèmes pour que ça marche. Je peux le convertir en une chaîne avec? cependant le fpdf le rejette toujours ...


Oui, j'ai aussi exécuté cela avec Python 3


Mes 'sortent tous à? .... avez-vous utilisé la méthode de substitution de police où vous définissez une police UTF 8?



3
votes

La raison de cette erreur est que vous essayez d'afficher un caractère de votre PDF qui se trouve en dehors de la plage de codes du codage latin-1 . FPDF utilise latin-1 comme encodage par défaut pour toutes ses polices intégrées.

Pour contourner le problème, vous pouvez simplement supprimer tous les caractères de votre texte qui ne rentrent pas dans latin-1 encodage. (voir mon autre réponse pour cette solution de contournement).

Pour corriger cette erreur et pouvoir rendre ces caractères dans votre PDF, vous devez utiliser des polices qui prennent en charge une plus large gamme de caractères. Pour résoudre ce problème, la bibliothèque FPDF prend en charge la police Unicode.

Par exemple, vous pouvez obtenir les polices Google Noto , qui prend en charge une large gamme de points de terminaison Unicode. Pour la plupart des langues occidentales, je recommanderais le jeu de polices NotoSans. Mais vous pouvez également obtenir des polices pour de nombreuses autres langues et scripts, y compris le chinois, l'hébreu ou l'arabe.

Voici comment activer les polices Unicode dans votre code pour FPDF:

Vous devez d'abord pour indiquer à la bibliothèque FPDF où elle peut trouver les fichiers de polices. Dans cet exemple, je le configure sur le sous-dossier polices du dossier actuel.

pdf.set_font("NotoSans", size=12)

Ensuite, vous devez ajouter les polices à votre PDF document. Dans cet exemple, j'ajoute les polices NotoSans pour les styles normal, gras, italique et gras-italique:

pdf = fpdf.FPDF()
pdf.add_font("NotoSans", style="", fname="NotoSans-Regular.ttf", uni=True)
pdf.add_font("NotoSans", style="B", fname="NotoSans-Bold.ttf", uni=True)
pdf.add_font("NotoSans", style="I", fname="NotoSans-Italic.ttf", uni=True)
pdf.add_font("NotoSans", style="BI", fname="NotoSans-BoldItalic.ttf", uni=True)

Vous pouvez maintenant utiliser les nouvelles polices normalement dans votre document PDF avec set_font () . Voici un exemple de texte normal:

import fpdf
fpdf.set_global("SYSTEM_TTFONTS", os.path.join(os.path.dirname(__file__),'fonts'))


0 commentaires

1
votes

Vous pouvez également modifier l'encodage via la méthode .set_doc_option () (documentation ici ). J'ai essayé la méthode d'Erik, qui a fonctionné pour moi, mais après avoir ajouté quelques complexités supplémentaires (comme un deuxième PDF et en utilisant la méthode write_html () qui nécessitait la création d'une nouvelle classe), je suis revenu à la même erreur. La modification de l'encodage de l'ensemble du document devrait résoudre le problème global comme vous l'avez dit.

La page readthedocs indique que vous ne pouvez utiliser que latin-1 ou windows-1252, mais pdf.set_doc_option ('core_fonts_encoding', 'utf-8') a fonctionné pour moi selon le débogueur. Sachez simplement que certains caractères devront être corrigés, comme l'apostrophe (') qui apparaît comme à ¢  € ÂTM dans le PDF.

J'espère que c'est la solution globale pour ce problème que vous recherchiez, même si plusieurs mois de retard!


0 commentaires