UTF-8 hexadezimal -> Zeichen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
aurikeL
User
Beiträge: 2
Registriert: Sonntag 25. Juli 2010, 09:28

Hallo Forum,

ich stehe zurzeit vor einem Problem, welches mich leicht stört. Ich habe mehrere Strings, die zB. so aussehen "M(c3bc)ll". Mein Ziel ist es nun, dass der String so aussieht: "Müll". Die Klammern stellen (natürlich) kein Problem dar, allerdings weiß ich nicht, wie ich das C3 BC zu einem "ü" umwandle - ich hab bisher folgendes herausgefunden: bei dem C3 BC handelt es sich um UTF-8 hexadezimal. Wisst ihr einen Rat?
(Python-Version: 2.3)

Gruß,
Max
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

aurikeL hat geschrieben:[...], allerdings weiß ich nicht, wie ich das C3 BC zu einem "ü" umwandle
Mit Python 2.6 (antike Versionen stehen mir nicht zur Verfügung) erhalte ich hiermit ein "ü":

Code: Alles auswählen

# -*- coding: utf-8 -*-
from __future__ import print_function
x1 = chr(0xC3)
x2 = chr(0xBC)
print(x1, x2)
a = x1 + x2
print(a)
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

Ja, das geht. Hab es etwas umständlich gelöst, vielleicht geht das noch besser:

Code: Alles auswählen

>>> c = 'c3bc'
>>> s = chr(int('0x%s' % c[:2], 16)) + chr(int('0x%s' % c[2:], 16))
>>> print s.decode("utf8")
ü
(Unter 2.6 getestet)
„Lieber von den Richtigen kritisiert als von den Falschen gelobt werden.“
Gerhard Kocher

http://ms4py.org/
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Stellt sich die Frage _wo_ du die hexadezimale Darstellung hast (im Allgemeinen sieht die `repr` Darstellung genau so aus, also wenn man z.b. Listen `print`et). Mehr Infos bitte.
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

cofi hat geschrieben:im Allgemeinen sieht die `repr` Darstellung genau so aus, also wenn man z.b. Listen `print`et
Also unter 2.6 nicht, ist das mit 2.3 so?

Code: Alles auswählen

>>> [s.decode("utf8")]
[u'\xfc']
„Lieber von den Richtigen kritisiert als von den Falschen gelobt werden.“
Gerhard Kocher

http://ms4py.org/
BlackJack

Code: Alles auswählen

import re


def replace_hex(string):
    def byte_sub(match):
        hex_digits_it = iter(match.group(0)[1:-1])
        return ''.join(chr(int(a + b, 16))
                       for a, b in zip(hex_digits_it, hex_digits_it))
    
    return re.sub(r'\(([0-9a-f]{2})+\)', byte_sub, string)


def main():
    old = 'M(c3bc)ll'
    new = replace_hex(old)
    print new


if __name__ == '__main__':
    main()
aurikeL
User
Beiträge: 2
Registriert: Sonntag 25. Juli 2010, 09:28

cofi hat geschrieben:Stellt sich die Frage _wo_ du die hexadezimale Darstellung hast (im Allgemeinen sieht die `repr` Darstellung genau so aus, also wenn man z.b. Listen `print`et). Mehr Infos bitte.
Danke für eure Antworten, ich werde sie am Montag testen.

An cofi: Ich lese über os.listdir() alle Ordner in einem bestimmten Verzeichnis aus und erstelle zu jedem Ordner eine neue Datei, dabei möchte ich allerdings, dass die hexadezimale Darstellung von Umlauten/Sondernzeichen(?) ersetzt wird. Ein Ordner würde dann zB. "M(c3bc)ll" heißen - die dazugehörige Datei soll allerdings "Müll" heißen.

Sollte es widererwartend Montag nicht klappen, so melde ich mich nochmal ..

.. schönes Wochenende. :)
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

BJ's Snippet etwas vereinfacht:

Code: Alles auswählen

#!/usr/bin/env python

import re

def replace_hex(string):
    def byte_sub(match):
        return ''.join(chr(int(a, 16)) for a in match.groups())
   
    return re.sub(r'\(([0-9a-f]{2})([0-9a-f]{2})\)', byte_sub, string)


def main():
    old = 'M(c3bc)ll'
    new = replace_hex(old)
    print new


if __name__ == '__main__':
    main()
„Lieber von den Richtigen kritisiert als von den Falschen gelobt werden.“
Gerhard Kocher

http://ms4py.org/
BlackJack

@ms4py: Etwas zu sehr vereinfacht, denn nicht alle UTF-8 Sequenzen sind nur zwei Bytes lang.
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

BlackJack hat geschrieben:@ms4py: Etwas zu sehr vereinfacht, denn nicht alle UTF-8 Sequenzen sind nur zwei Bytes lang.
Ja, du hast Recht. Aber in diesem Anwendungsfall müsste es reichen.

Deine `iter`-Lösung finde ich jedenfalls zu magisch. Vielleicht gibt es auch eine bessere Lösung um immer zwei Elemente aus dem String zu nehmen?
„Lieber von den Richtigen kritisiert als von den Falschen gelobt werden.“
Gerhard Kocher

http://ms4py.org/
BlackJack

@ms4py: Slicing und über Indexe in Zweierschritten ginge. Andererseits ist so eine "zu magische" Lösung irgendwo in der Python-Doku wenn ich mich recht erinnere.
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

BlackJack hat geschrieben:@ms4py: Slicing und über Indexe in Zweierschritten ginge. Andererseits ist so eine "zu magische" Lösung irgendwo in der Python-Doku wenn ich mich recht erinnere.
Naja, damit ist auch nicht wirklich besser (oder geht das noch besser?)

Code: Alles auswählen

from itertools import izip

def split_in_two(string):
    for a, b in izip(string[::2], string[1::2]):
        yield a+b
Bei dir ist diese Funktion eben so "magisch" versteckt.
Auslagern in eine Funktion wäre im Prinzip auch schon in Ordnung ;)
„Lieber von den Richtigen kritisiert als von den Falschen gelobt werden.“
Gerhard Kocher

http://ms4py.org/
BlackJack

@ms4py: Ich dachte mehr an sowas:

Code: Alles auswählen

In [464]: list(string[i:i + 2] for i in xrange(0, len(string), 2))
Out[464]: ['c3', 'bc']
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

So geht's mit Python 3.x:

Code: Alles auswählen

import re

def decode(s):
    return re.sub(r"\(([0-9A-Fa-f]+)\)", lambda m:bytes.fromhex(m.group(1)).decode("utf-8"), s)

print(decode('M(C3BC)ll (C384)rger'))
und für Python 2.x kann das Lambda so aussehen (und der übergebene String sollte natürlich ein echter String sein, d.h. ein "u" vorangestellt bekommen):

Code: Alles auswählen

lambda m:m.group(1).decode("hex").decode("utf-8")
Stefan
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@ms4py:

Das kommt dir vermutlich nur so magisch vor, weil dieser Einsatz von `iter()`, bei dem nämlich eine Funktion aufgerufen wird, nicht so geläufig ist. Wenn man sich erstmal daran gewöhnt hat, kann eine `iter()`-Lösung viele `while True: [...] break`-Konstrukte ersetzen, was letztlich schöner aussieht.
BlackJack

@snafu: Ich glaube Du verwechselst da etwas. So wird `iter()` hier nicht eingesetzt. Was ms4py zu magisch findet, ist, dass in einem `zip()` zweimal der selbe Iterator benutzt wird um Paare zu erzeugen.
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Stimmt, es wird ja lediglich das *Ergebnis* einer Funktion verwendet. :oops:
Antworten