Warnung ausgelöst durch Einfügen von 4-Byte-Unicode in mysql

Schau dir folgendes an:

/home/kinka/workspace/py/tutorial/tutorial/pipelines.py:33: Warning: Incorrect string 
value: '\xF0\x9F\x91\x8A\xF0\x9F...' for column 't_content' at row 1
n = self.cursor.execute(self.sql, (item['topic'], item['url'], item['content']))

Die Saite'\xF0\x9F\x91\x8Aist eigentlich ein 4-Byte-Unicode:u'\U0001f62a'. Der Zeichensatz von mysql ist utf-8, aber das Einfügen von 4-Byte-Unicode schneidet die eingefügte Zeichenfolge ab. Ich habe nach einem solchen Problem gegoogelt und festgestellt, dass mysql unter 5.5.3 keinen 4-Byte-Unicode unterstützt, und leider ist meins 5.5.224. Ich möchte den MySQL-Server nicht aktualisieren, daher möchte ich nur den 4-Byte-Unicode in Python filtern. Ich habe versucht, einen regulären Ausdruck zu verwenden, bin jedoch gescheitert. Also, irgendeine Hilfe?

 mata29. Mai 2012, 14:01
@MartijnPieters -unicodedata.name("\U0001f62a") sagt'SLEEPY FACE' (welches sein würdeb'\xf0\x9f\x98\xaa' in utf-8), also hier stimmt etwas nicht ...
 Kinka29. Mai 2012, 14:08
Eigentlich ist es ein schläfriges Gesicht. Ich schabe Seiten aussina weibo(twitter in China), und ich habe solche geschabtSLEEP FACE.
 Martijn Pieters29. Mai 2012, 14:54
Ja, und'\xF0\x9F\x91\x8A'.decode('utf8') istu'\U0001f44a', welches ist'FISTED HAND SIGN' :-)
 Martijn Pieters29. Mai 2012, 13:59
Das ist das FISTED HAND SIGN Farb-Emoji:👊...

Antworten auf die Frage(3)

def normalize_unicode(s):
    return ''.join([ unichr(k) if k < 0x10000 else 0xfffd for k in [ord(c) for c in s]])
Lösung für das Problem

müssen Sie alle Unicode-Zeichen über den Codepunkt herausfiltern\U00010000; UTF-8 codiert Codepunkte unterhalb dieses Schwellenwerts in 3 Byte oder weniger.

Sie könnten dafür einen regulären Ausdruck verwenden:

>>> import re
>>> highpoints = re.compile(u'[\U00010000-\U0010ffff]')
>>> example = u'Some example text with a sleepy face: \U0001f62a'
>>> highpoints.sub(u'', example)
u'Some example text with a sleepy face: '

Alternativ können Sie auch die.translate() Funktion mit einer Zuordnungstabelle, die nur enthältNone Werte:

>>> nohigh = { i: None for i in xrange(0x10000, 0x110000) }
>>> example.translate(nohigh)
u'Some example text with a sleepy face: '

Das Erstellen der Übersetzungstabelle beansprucht jedoch viel Speicher und benötigt einige Zeit zum Generieren. es lohnt sich wahrscheinlich nicht, da der Ansatz mit regulären Ausdrücken effizienter ist.

Dies setzt voraus, dass Sie ein UCS-4-kompiliertes Python verwenden. Wenn Ihr Python mit UCS-2-Unterstützung kompiliert wurde, können Sie nur Codepoints bis zu verwenden'\U0000ffff' in regulären Ausdrücken und Sie werden nie in erster Linie auf dieses Problem stoßen.

Ich stelle fest, dass ab MySQL 5.5.3 das neu hinzugekommen istutf8mb4 Codec Unterstützt den gesamten Unicode-Bereich.

 Martijn Pieters05. Sept. 2012, 21:30
@MichaelWaterfall: Doimport sys; print sys.maxunicode. Wenn du bekommst65535 es ist ein UCS-2 Build,1114111 für einen breiten UCS-4 Build.
 Michael Waterfall07. Sept. 2012, 16:07
@MartijnPieters Danke für die tollen Infos. Das war mir eigentlich gerade aufgefallenlen(u'\U0001f3b6') == 2 und vermutet, dass dies durch die UCS-2-Version von Python verursacht wurde. Zeit für ein Update! Danke noch einmal.
 Martijn Pieters05. Sept. 2012, 21:27
@MichaelWaterfall: Ich bin nicht sicher, wie das alles gehandhabt wird; Ein UCS2-Build kann eine 4-Byte-Unicode-Zeichenfolge drucken, das Modul für reguläre Ausdrücke kann sie jedoch nicht ordnungsgemäß verarbeiten, da die interne Darstellung sie nicht verarbeiten kann.
 Martijn Pieters05. Sept. 2012, 21:42
@MichaelWaterfall: Bei einem UCS-2-Build ist dieses Zeichen tatsächlich2 Bytes unter Verwendung eines UTF-16-Ersatzes;len(u'\U0001f3b6') == 2 auf einem solchen Build. Auf einem UCS-4-Build ist eslen(u'\U0001f3b6') == 1..
 Martijn Pieters29. Mai 2012, 15:10
Du liegst ziemlich richtig; korrigiert, um korrekte 8-Byte-Escape-Sequenzen zu verwenden. Anfangs hatte ich einige Probleme wegen der Verwendung eines UCS2-kompilierten Pythons :-P
 Kinka29. Mai 2012, 14:59
Ich habe Ihren Code ausprobiert, aber es funktioniert nicht. Es ist\U(Großbuchstabenu). Ihr Gedanke ist jedoch wirklich aufschlussreich, danke!
 Kinka29. Mai 2012, 15:12
Aber in meinem Fall ist es wirklich wichtig, ob es sich um Kleinbuchstaben handelt oder nicht. Was ich benutze isthighpoints = re.compile(u'[\U00010000-\U0001ffff]') und es funktioniert. Es scheint, dass in meinem Computer (ist es das Problem der Version von Python? Meins ist Python 2.7). Mit Großbuchstaben\Uunterstützt der Unicode eine viel größere Reichweite.
 Michael Waterfall05. Sept. 2012, 20:33
Eine Idee, warum ich einen Fehler erhalte mit:re.compile(u'[\U00010000-\U0010ffff]') "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/re.py", line 244, in _compile raise error, v # invalid expression sre_constants.error: bad character range
 Martijn Pieters05. Sept. 2012, 21:28
@MichaelWaterfall: In einem UCS-4-Build können Sie den regulären Ausdruck kompilieren, in einem UCS-2-Build nicht. Python 3.3 hebt übrigens die Unterscheidung auf, sodass Hoffnung für die Zukunft besteht. :-)
 Martijn Pieters05. Sept. 2012, 20:38
@MichaelWaterfall: Sie haben ein UCS2 (2-Byte-Unicode) kompiliertes Python; Es werden nur Unicode-Werte bis zu unterstützt\uffff.
 Michael Waterfall05. Sept. 2012, 20:44
Ah okay, danke! Aus Interesse also, warum?print(u'\U0001f3b6') das richtige Emoji-Zeichen anzeigen (4 Byte)?
 Martijn Pieters29. Mai 2012, 15:12
Nein, du bist ganz richtig. Ich habe gerade auch die Untergrenze gesenkt und festgestellt, dass ich die UTF-8-Tabelle falsch gelesen habe.

Sie sollten utf8mb4 Kollatierung anstelle von utf8 verwenden und ausführen

SET NAMES UTF8MB4

nach Verbindung mit DB (Verknüpfung, Verknüpfung, Verknüpfung)

 bobince23. Juli 2015, 13:38
Festlegen der zu verwendenden Verbindungutf8mb4 ist der beste Ansatz, aber Sie sollten es nicht mit tunSET NAMES. Dieser Befehl ändert die Verbindungseinstellung auf der Serverseite, ohne die Clientbibliothek über die Änderung zu informierenmysql_real_escape_string API kann zu schlechten Ergebnissen führen. Dies kann zu Sicherheitslücken bei der SQL-Injektion führen, wenn es sich bei einer ostasiatischen Multibyte-Codierung um einen oder beide Zeichensätze handelt. Zeichensätze sollten zum Zeitpunkt der Verbindung festgelegt werden. in python-mysql würde dies mit dercharset Argument zuconnect().

Ihre Antwort auf die Frage