Seite 1 von 1

Fehlerhapfte String Formatierung (Einst%C3%BCrzende)

Verfasst: Donnerstag 6. November 2008, 13:00
von Barabbas
Hallo zusammen!

Ich schreibe gerade einen kleinen Cover Downloader für Amazon Cover. Dabei wird eine Verzeichnisstruktur rekursiv ausgelesen und im Falle eines nicht vorhandenen Covers für ein Verzeichnis dieses von Amazon geholt. Da die Verzeichnisse nach dem Schema "Künstler/Album" benannt sind, splitte ich das Verzeichnis einfach auf und suche über die Amazon REST API danach.

Mein Problem ist nun: Ich schaffe es nicht, Verzeichnisse mit Sonderzeichen (Umlaute...) korrekt an Amazon zu übertragen.

Wenn ich es mit urllib.urlencode() mache, wird es wie folgt verschlüsselt:
Einstürzende => Einst%C3%BCrzende. Bei Amazon landet Einstürzende und führt natürlich zu keinem Ergebnis.
Das gleiche passiert, wenn ich urlencode() völlig weg lasse: Dann steht in der URL Klartext "Einstürzende", bei Amazon landet aber wieder Einstürzende.

Hat jemand von euch eine Idee, wie ich den String so formatieren könnte, dass er bei Amazon richtig ankommt?

lG

brb

Verfasst: Donnerstag 6. November 2008, 13:10
von HWK
Das Encoding bei Amazon ist wohl nicht UTF-8 wie bei Dir. Du müßtest den String erst im Encoding von Amazon encodieren und dann urlencoded versenden.

Code: Alles auswählen

>>> urlencode({'test':'Einstürzende'.decode('cp1252').encode('utf-8')})
'test=Einst%C3%BCrzende'
Du musst also nur noch das benötigte Encoding herausfinden. :wink:
MfG
HWK

Verfasst: Donnerstag 6. November 2008, 15:43
von Barabbas
Es scheint, als ob urllib.urlencode() anders enkodiert als Amazon es erwartet. Ich habe einfach folgende "hau mich ich kann nix" Variante ersonnen, die für die von mir getesteten Fälle funktioniert (umlaute, leerzeichen etc).

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

codes = {
    " " : "%20",
    "!" : "%21",
    "\"" : "%22",
    "#" : "%23",
    "$" : "%24",
    "%" : "%25",
    "&" : "%26",
    "'" : "%27",
    "(" : "%28",
    ")" : "%29",
    "*" : "%2A",
    "+" : "%2B",
    "," : "%2C",
    "-" : "%2D",
    "." : "%2E",
    "/" : "%2F",
    ":" : "%3A",
    ";" : "%3B",
    "<" : "%3C",
    "=" : "%3D",
    ">" : "%3E",
    "?" : "%3F",
    "@" : "%40",
    "[" : "%5B",
    "\\" : "%5C",
    "]" : "%5D",
    "^" : "%5E",
    "_" : "%5F",
    "`" : "%60",
    "{" : "%7B",
    "|" : "%7C",
    "}" : "%7D",
    "~" : "%7E",
    " " : "%7F",
    "€" : "%80",
    " " : "%81",
    "‚" : "%82",
    "ƒ" : "%83",
    "„" : "%84",
    "…" : "%85",
    "†" : "%86",
    "‡" : "%87",
    "ˆ" : "%88",
    "‰" : "%89",
    "Š" : "%8A",
    "‹" : "%8B",
    "Œ" : "%8C",
    " " : "%8D",
    "Ž" : "%8E",
    " " : "%8F",
    " " : "%90",
    "‘" : "%91",
    "’" : "%92",
    "“" : "%93",
    "”" : "%94",
    "•" : "%95",
    "–" : "%96",
    "—" : "%97",
    "˜" : "%98",
    "™" : "%99",
    "š" : "%9A",
    "›" : "%9B",
    "œ" : "%9C",
    " " : "%9D",
    "ž" : "%9E",
    "Ÿ" : "%9F",
    " " : "%A0",
    "¡" : "%A1",
    "¢" : "%A2",
    "£" : "%A3",
    " " : "%A4",
    "¥" : "%A5",
    "|" : "%A6",
    "§" : "%A7",
    "¨" : "%A8",
    "©" : "%A9",
    "ª" : "%AA",
    "«" : "%AB",
    "¬" : "%AC",
    "¯" : "%AD",
    "®" : "%AE",
    "¯" : "%AF",
    "°" : "%B0",
    "±" : "%B1",
    "²" : "%B2",
    "³" : "%B3",
    "´" : "%B4",
    "µ" : "%B5",
    "¶" : "%B6",
    "·" : "%B7",
    "¸" : "%B8",
    "¹" : "%B9",
    "º" : "%BA",
    "»" : "%BB",
    "¼" : "%BC",
    "½" : "%BD",
    "¾" : "%BE",
    "¿" : "%BF",
    "À" : "%C0",
    "Á" : "%C1",
    "Â" : "%C2",
    "Ã" : "%C3",
    "Ä" : "%C4",
    "Å" : "%C5",
    "Æ" : "%C6",
    "Ç" : "%C7",
    "È" : "%C8",
    "É" : "%C9",
    "Ê" : "%CA",
    "Ë" : "%CB",
    "Ì" : "%CC",
    "Í" : "%CD",
    "Î" : "%CE",
    "Ï" : "%CF",
    "Ð" : "%D0",
    "Ñ" : "%D1",
    "Ò" : "%D2",
    "Ó" : "%D3",
    "Ô" : "%D4",
    "Õ" : "%D5",
    "Ö" : "%D6",
    " " : "%20", #%D7
    "Ø" : "%D8",
    "Ù" : "%D9",
    "Ú" : "%DA",
    "Û" : "%DB",
    "Ü" : "%DC",
    "Ý" : "%DD",
    "Þ" : "%DE",
    "ß" : "%DF",
    "à" : "%E0",
    "á" : "%E1",
    "â" : "%E2",
    "ã" : "%E3",
    "ä" : "%E4",
    "å" : "%E5",
    "æ" : "%E6",
    "ç" : "%E7",
    "è" : "%E8",
    "é" : "%E9",
    "ê" : "%EA",
    "ë" : "%EB",
    "ì" : "%EC",
    "í" : "%ED",
    "î" : "%EE",
    "ï" : "%EF",
    "ð" : "%F0",
    "ñ" : "%F1",
    "ò" : "%F2",
    "ó" : "%F3",
    "ô" : "%F4",
    "õ" : "%F5",
    "ö" : "%F6",
    "÷" : "%F7",
    "ø" : "%F8",
    "ù" : "%F9",
    "ú" : "%FA",
    "û" : "%FB",
    "ü" : "%FC",
    "ý" : "%FD",
    "þ" : "%FE",
    "ÿ" : "%FF"
}

def urlencode(text):
    text = text.replace("%", codes["%"])
    for code in codes:
        if code in text and code != "%":
            print code
            text = text.replace(code, codes[code])
    return text
Folgende Anmerkungen: Viele normale Buchstaben und Zahlen habe ich entfernt, prinzipiell hat natürlich jeder Buchstabe seine Entsprechung. Zuerst werden natürlich alle "%" ersetzt, da diese später ein kodiertes Zeichen einleiten und dann nicht mehr ersetzt werden sollen.
In dieser Variante wird jetzt jedes Zeichen im Dict darauf getestet, ob es im String vorkommt und dann ggf. ersetzt.

Wie ich gerade feststelle, werden die Zeichen nach dem Schema "'%%%i' % ord(char)" formatiert. Oben genannter Code kann also deutlich gestrafft werden.

lG

brb

Verfasst: Donnerstag 6. November 2008, 16:53
von BlackJack
@Barabbas: Bravo Du hast `urlencode()` umständlich nachgebaut. Das Problem ist die Kodierung des (Byte)Strings bevor Du `urlencode()` aufrufst.

Verfasst: Donnerstag 6. November 2008, 17:39
von Barabbas
wenn ich den selben string einmal an urlencode() und einmal an mein_urlencode() übergebe, erhalte ich unterschiedliche Ergebnisse.
Das Eine ist unbrauchbar, das Andere nicht. Da ich bisher keine Kodierung finden konnte, die funktioniert, betrachte ich obigen Code vorerst als Lösung, bis es eine Bessere gibt.

Verfasst: Donnerstag 6. November 2008, 18:13
von BlackJack
Okay, dann ist der Quelltext also UTF-8 kodiert und die Schlüssel sind nicht alle 1 Byte lang. Da habe ich mich von der Aussage mit `ord()` irritieren lassen. *Das* wäre nämlich das was `urlencode()` macht.

Die Kodierung ist ISO-8859-15. Stand das nicht bei der Tabelle, wo Du die Codes abgetippt hast? Oder wie bist Du auf die Werte gekommen?

Verfasst: Donnerstag 6. November 2008, 18:33
von Barabbas
Die Werte habe ich tatsächlich aus einer Tabelle, die ich irgendwo in der Amazon-Dokumentation gefunden habe. Dort wurde auf diese Seite verlinkt.

So wie ich das verstehe sind die Werte einfach nur die Hex-Werte des entsprechenden Ansi-Zeichencodes. Ich habe auch keine Ahnung, warum urllib.urlencode() da zu anderen Ergebnissen kommt, habe - wie gesagt- schon die geläufigsten Kodierungen getestet.


---
Hm, mit iso-8859-15 geht es tatsächlich. Ich hatte das schon probiert, aber anscheinend dekodiert statt enkodiert. Blöder Fehler aber jetzt geht es; Amazon spezifiziert zwar das Zeichen "%20" für Leerzeichen aber mit "+" geht es anscheinend auch. Scheint zu gehen.

Danke dir!

Verfasst: Freitag 7. November 2008, 14:18
von Y0Gi
`%20` ist das URL-Encoding eines Leerzeichens, aber es gibt auch das "Plus-Quoting", bei dem ein `+` als Maskierung dient. Das ist beides nichts Amazon-Spezifisches.

Verfasst: Samstag 8. November 2008, 08:49
von sma
Nein, die selbstgemachte Kodierung dort ist nicht ISO-8859-15 (aka Latin-9) sondern das Windows-spezifische CP1252. Bei ISO-8859-15 würde das €-Zeichen auf A4 liegen (und das internationale Währungssymbol ¤ von ISO-8859-1 (Latin-1) ersetzen) sowie noch ein paar andere Unterschiede haben. Die zitierte Tabelle titelt mit "ASCII-Charakter" die Spalte falsch, denn der ASCII-Code endet bei 127. Im Text wird zudem fälschlich ISO-8859-1 erwähnt. Die Seite ist Müll.

Stefan

Verfasst: Samstag 8. November 2008, 23:39
von Barabbas
auch wenn es unprofessionell wirkt (was den Tatsachen entspräche, da ich das Ganze ja nur aus Jux und Dollerei betreibe): Ich habe diesem ganzen Sprach-String-Zeichenketten-Formatierungs-Kram schon immer sehr ahnungslos gegenüber gestanden. Irgendwie wirkt der Beitrag von sma ziemlich... absurd (natürlich nur auf mich, da ich ja davon auch herzlich wenig verstehe).
Punktum, danke für eure Hilfe es läuft und bei Zeiten werde ich Bericht erstatten, was Amazon nun tatswahrhaftig erwartet.

@Yogi: Das mit %20 und + kenne ich auch, schon klar, dass Amazon das nicht erfunden hat. Mit "amazon spezifiziert..." meinte ich nur, dass Amazon schreibt, dass die API das so erwartet. Streng genommen spezifizieren die also nicht das urlencoding sondern die String-Verarbeitung der API, da hast du natürlich recht.

Verfasst: Sonntag 9. November 2008, 01:00
von Leonidas
Barabbas hat geschrieben:auch wenn es unprofessionell wirkt (was den Tatsachen entspräche, da ich das Ganze ja nur aus Jux und Dollerei betreibe): Ich habe diesem ganzen Sprach-String-Zeichenketten-Formatierungs-Kram schon immer sehr ahnungslos gegenüber gestanden. Irgendwie wirkt der Beitrag von sma ziemlich... absurd (natürlich nur auf mich, da ich ja davon auch herzlich wenig verstehe).
Wenn du dich nicht damit beschäftigst was sma da genau schreibt, was das bedeutet etc. dann wird es auch immer absurd bleiben. Unverständnis ist nicht unprofessionell. Mangel an besserungswillen ist schon eher unprofessionell. Und solltest dich besser mal mit den Unicode-Ressourcen im Wiki bekannt machen, es gibt mindestens zwei Artikel dazu und auch meine Folien die zum Verständiss hilfreich sein könnten. Außerdem die Forensuche. Wenn du keine passenden Antworten findest, dann darfst du natürlich auch neue Threads starten und dort Fragen stellen - Fragen bei denen der Autor schon vorher die vorhandenen Ressourcen ausgeschöpft hat und selbst rumprobiert hat sich natürlich gern gesehen und helfen vielleicht auch anderen die in Zukunft die selbe Frage haben könnten.