special characters HTML und Unicode

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
Benutzeravatar
snafu
User
Beiträge: 6741
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Sirius3 hat geschrieben:Als sortkey kannst Du gleich locale.strxfrm nehmen.
Mit `locale.strxfrm` wirft er mir eine Exception bei Unicode-Strings, die außerhalb des ASCII-Zeichensatzes sind (also z.B. deutsche Umlaute).

Code: Alles auswählen

Python 2.7.9 (default, Dec 10 2014, 12:24:55) [MSC v.1500 32 bit (Intel)] on win
32
Type "help", "copyright", "credits" or "license" for more information.
>>> import locale
>>> locale.setlocale(locale.LC_COLLATE, '')
'German_Germany.1252'
>>> sorted([u'bämm'], key=locale.strxfrm)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe4' in position 1:
ordinal not in range(128)
Daher bin ich bewusst den anderen Weg gegangen.
Wenn Du still und heimlich immer auf den non-locale-sort umsteigst, wirst Du nie fehler beim locale-Namen finden und Dich immer nur wundern, warum die Sortierung nicht funktioniert. Zumindest eine Warning sollte man ausgeben.
Ganz so ist es ja nicht. Man kann den `strict`-Parameter nutzen und würde den Fehler dann sehen. Für meine Zwecke war es eben wichtiger, überhaupt ein Ergebnis zu haben, selbst wenn das Ändern der `locale`-Einstellungen schiefgegangen ist. Das Ausgeben einer Warnung ist allerdings keine schlechte Idee.
Daikoku
User
Beiträge: 66
Registriert: Montag 20. April 2015, 21:14

zuerst einmal vielen Dank für die Ideen und Gedanken, die Ihr Euch alle gemacht habt.

Das Thema HTML Entities ist erledigt, das Ergebnis habe ich in einem separaten Threat zusammengefasst. http://www.python-forum.de/viewtopic.php?f=1&t=36604


Bleibt das Thema Sonderzeichen.

Ich muss ehrlich gestehen, das mich diese Komplexität ein wenig überrascht hat.

Ich habe einmal die Ressourcen meiner Firma genutzt und nachgeschaut, wie wir dieses Problem handhaben und das ist erschreckend einfach :

Ich kann in meinem System sehr genau hinterlegen, wie ich was sortiert haben möchte.

Beispiel : Lodz und Łódź

Es gibt eine Tabelle, wo vereinfacht dargestellt, das wie folgt hinterlegt ist : A;B;C;D;E;F;G;H;I;J:K;L;Ł;M ......

Damit ist festgelegt, das Ł nach L kommt. Das Ganze geht noch viel detaillierter, aber das soll hier jetzt nicht das Thema sein.

Nachdem das so eingetragen wurde, ist es nun auch völlig egal, ob ich mir meine Daten, auf einem SmartPhone, Tablet, Mac, PC oder
auf was auch immer auswerten lasse, die Sortierung ist immer gleich. Selbst dann, wenn ich die Spracheinstellung von deutsch auf zum Beispiel japanisch ändere.
Jeder User kann seine ganz individuelle Sortierung hinterlegen.
Es gibt aber auch, für einige Reports einheitliche Sortierungen, die zentral festgelegt werden, und vom User nicht übersteuert werden können.

Auf meinem SmartPhone und Tablet habe ich u.a. Sybase SQL Anywhere laufen und über meinen PC greife ich auf die selben Daten in HANA, Oracle oder DB/2 zu
und erhalte von meiner Applikation, die Daten immer in der gewünschten Reihenfolge.

Ich habe auf den verschiedenen Datenbanken eine entsprechende Tabellen angelegt und diese dann, von der jeweiligen Datenbanken selber sortieren lassen.
Dabei habe ich festgestellt, das völlig unterschiedliche Ergebnis, bei gleichem Datenbestand heraus kommen.


Für mich bedeutet das, das die Sortierung immer von der Applikation gesteuert wird, völlig unabhängig vom Betriebssystem, der Programmiersprache oder der jeweiligen Datenbank.

Damit komme ich zu folgendem Ergebnis.

Ich muss festlegen, wie ich etwas sortiert haben möchte und muss gleichzeitig sicherstellen, das diese Vorgaben auch immer eingehalten werden.
Ein einfaches sorted() oder SELECT from …. ORDER BY … wird das so nicht leisten können.

Meine Tests haben auch gezeigt, das es unterschiedliche Sortierroutinen gibt. Wer weiß, ob das in Python immer so bleibt, wie es jetzt gerade ist, oder ob nicht irgendwann einmal, jemand auf die Idee kommt, eine völlig andere Routine zu implementieren und schon habe ich dann völlig andere Ergebnisse.

Wenn ich einmal nach vorne schaue, ergibt sich für mich noch ein weiteres Problem. Wenn ich zum Beispiel meine Daten von Python nach HTML rendern lasse darf die Sortierung der Daten zu keinem anderen Ergebnis führen, als wenn ich das, über ECMAScript direkt im Browser umsetzen würde.

Ich muss mir noch ein paar weiter gehende Gedanken machen :

Orte haben unterschiedliche Namen :
- Breslau = Wrocław
- Danzig = Gdańsk
- Stettin = Szczecin
- Wien = Vienna

Ich könnte mir vorstellen, das es zum Beispiel für die EU einheitliche Städte Bezeichnungen gibt. Gibt es Konventionen für Ortsbezeichnungen ? Es kann eigentlich nicht sein, das in Dokumenten eines Projektes zum Beispiel einmal von Breslau und in einem weiteren Dokument plötzlich von Wrocław die Rede ist, je nachdem wer dieses gerade verfasst hat. Das führt doch zu Verwirrungen, oder ist das jedem sofort klar das Breslau gleich Wrocław ist. Also mir nicht. Und wie gebe ich überhaupt Wrocław über meine Tastatur ein. Klar ich kann das Layout softwaretechnisch ändern, aber meine physikalische Tastatur ist immer noch die gleiche. Woher soll ich jetzt wissen, welche Taste das Zeichen ł darstellt. Auf meinem Tablet ist das alles gar kein Problem. Aber bei meinen Notebook und PC schon.

Fragen über Fragen. Ich muss diese erst einmal alle für mich klären, aber gleichzeitig auch vermeiden, das diese Aufgabenstellung ungewollt zu einem größeren Problem mutiert, als es vielleicht in Wirklichkeit ist.

Wie gehe ich jetzt weiter vor :

Bevor ich mich mit der Sortierung weitergehend beschäftige, brauche ich erst einmal saubere Daten.

Code: Alles auswählen

a = '\xc5\x81\xc3\xb3d\xc5\xba' # ist gleich mit a = 'Łódź'
b = {a:a}       # b = {'\xc5\x81\xc3\xb3d\xc5\xba': '\xc5\x81\xc3\xb3d\xc5\xba'}
print b['Łódź'] # out : \xc5\x81\xc3\xb3d\xc5\xba
print b['\xc5\x81\xc3\xb3d\xc5\xba'] # out : \xc5\x81\xc3\xb3d\xc5\xba

Code: Alles auswählen

a = '&emsp;&emsp;\xc5\x81\xc3\xb3d\xc5\xba&emsp;&emsp;' # ist gleich mit a = '  Łódź  '
b = {a:a}       # b = {'&emsp;&emsp;\xc5\x81\xc3\xb3d\xc5\xba&emsp;&emsp;': '&emsp;&emsp;\xc5\x81\xc3\xb3d\xc5\xba&emsp;&emsp;'}
print b['Łódź'] # out : KeyError: '\xc5\x81\xc3\xb3d\xc5\xba'
print b['\xc5\x81\xc3\xb3d\xc5\xba'] # out : KeyError: '\xc5\x81\xc3\xb3d\xc5\xba'
Das Beispiel zeigt, das ich meine Daten in jedem Fall, von den HTML-Entitäten befreien muss und anschließend von ungewollten Leerzeichen.
Nachstehend nur mal eine Idee, ohne Funktionen und sonstigen Strukturen.

Code: Alles auswählen

entity = { '&nbsp;'  : ' ',  # erzwungenes Leerzeichen
           '&ensp'   : ' ',  # Leerzeichen Breite n
           '&emsp'   : ' '  # Leerzeichen Breite m
          }

decode  = dict((re.escape(k), v) for k, v in entity.iteritems())
pattern = re.compile("|".join(decode.keys()))

text = '&emsp;&emsp;\xc5\x81\xc3\xb3d\xc5\xba&emsp;&emsp;'

text = pattern.sub(lambda m: decode[re.escape(m.group(0))], text)

# Alle doppelten Leerzeichen, sowie die Leerzeichen am Anfang und am Ende entfernen.
text = ' '.join(text.split())
Ich weiß, dass ich auch gleich so etwas wie :

Code: Alles auswählen

re.compile('&([a-zA-Z][-.a-zA-Z0-9]*)[^a-zA-Z0-9]')
verwenden kann. Bitte seht mir hier eventuelle Fehler nach, ich muss mich mit re noch intensiver beschäftigen.

Warum ich mich gegen den vermeintlich einfacheren Weg entschieden habe :
Das ich die values und keys aus entity später einmal über eine GUI verwalten möchte.
Also nicht einfach fest in einem Modul. Ich habe irgendwo gelesen, das man dieses dann hardcoded nennt ?
Ist auch egal, ich möchtet das nicht irgendwo fest verdrahtet haben, sondern flexibel halten.

zum Beispiel kann ich dann aus Müll auch noch etwas sinnvolles machen.
'&emsp;&#204Berlin&xp&gst;' = 'Berlin'
ohne ständig den Code selber zu ändern.

Darüber hinaus stellt sich die Frage, wenn entity jetzt zum Beispiel 1000 Keys hat und ich dann 1, 10, 100 Million Textstrings damit verarbeite,
wie sieht das Laufzeitverhalten aus. Brauche ich eine Vorprüfung ? if '&' in text: then; oder nehme ich einfach alle Textstrings und
lasse diese durch die Routine laufen.
Ist das multiprocessing fähig und ab wie vielen Textstrings ist das überhaupt sinnvoll.
threads bringen unter Windows nichts, ausser ich möchte es langsamer machen als eigentlich wäre.
Ich werde das alles mal testen.

Der nächste Schritt wäre dann, der Umgang mit den Ortsbezeichnungen.

Ich schaue mir auch auf jeden Fall Eure Vorschläge alle an, z.B. habe ich locale noch nie verwendet. Da muss ich mal lesen.
Bei mir geht nichts verloren, aber ich brauche ein wenig Zeit zum Nachdenken, recherchieren, lesen, usw. um ein wenig Struktur hier rein zu bekommen.
Ich werde auf das Thema wieder zurück kommen.

Vielen Dank für Eure Anregungen und Mühen.
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

@Daikoku: Warum erfindest Du Dir jetzt eine eigenes HTMLEntry-Unencode?
Schau doch, wie es andere machen: statt etliche verschieden Entities zu suchen, solltest Du einen generischen Ausdruck nehmen, und die unicode Codepoints unterstützt Du auch noch nicht:

Code: Alles auswählen

ENTITY_EXPR = re.compile('&#X[0-9A-F]+;|&#[0-9]+;|&\w+;', re.I)

def unescape(text):
    def replace(match):
        s = match.group(0)
        if s[1] == "#":
            if s[2] in "xX":
                c = int(s[2:], 16)
            else:
                c = int(s[1:])
            return unichr(c)
        else:
            return entity.get(s, s)
    return ENTITY_EXPR.sub(replace, text)
Antworten