Seite 1 von 1

UTF-8 hexadezimal -> Zeichen

Verfasst: Freitag 30. Juli 2010, 14:01
von aurikeL
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

Re: UTF-8 hexadezimal -> Zeichen

Verfasst: Freitag 30. Juli 2010, 14:26
von /me
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)

Re: UTF-8 hexadezimal -> Zeichen

Verfasst: Freitag 30. Juli 2010, 14:31
von ms4py
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)

Re: UTF-8 hexadezimal -> Zeichen

Verfasst: Freitag 30. Juli 2010, 14:32
von cofi
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.

Re: UTF-8 hexadezimal -> Zeichen

Verfasst: Freitag 30. Juli 2010, 14:36
von ms4py
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']

Re: UTF-8 hexadezimal -> Zeichen

Verfasst: Freitag 30. Juli 2010, 14:42
von 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()

Re: UTF-8 hexadezimal -> Zeichen

Verfasst: Freitag 30. Juli 2010, 15:51
von aurikeL
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. :)

Re: UTF-8 hexadezimal -> Zeichen

Verfasst: Freitag 30. Juli 2010, 15:54
von ms4py
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()

Re: UTF-8 hexadezimal -> Zeichen

Verfasst: Freitag 30. Juli 2010, 15:58
von BlackJack
@ms4py: Etwas zu sehr vereinfacht, denn nicht alle UTF-8 Sequenzen sind nur zwei Bytes lang.

Re: UTF-8 hexadezimal -> Zeichen

Verfasst: Freitag 30. Juli 2010, 17:01
von ms4py
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?

Re: UTF-8 hexadezimal -> Zeichen

Verfasst: Freitag 30. Juli 2010, 17:31
von 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.

Re: UTF-8 hexadezimal -> Zeichen

Verfasst: Freitag 30. Juli 2010, 17:43
von ms4py
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 ;)

Re: UTF-8 hexadezimal -> Zeichen

Verfasst: Freitag 30. Juli 2010, 17:49
von 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']

Re: UTF-8 hexadezimal -> Zeichen

Verfasst: Samstag 31. Juli 2010, 08:35
von sma
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

Re: UTF-8 hexadezimal -> Zeichen

Verfasst: Samstag 31. Juli 2010, 09:22
von snafu
@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.

Re: UTF-8 hexadezimal -> Zeichen

Verfasst: Samstag 31. Juli 2010, 09:43
von 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.

Re: UTF-8 hexadezimal -> Zeichen

Verfasst: Samstag 31. Juli 2010, 10:01
von snafu
Stimmt, es wird ja lediglich das *Ergebnis* einer Funktion verwendet. :oops: