2012-12-05 12 views
12

Mam aplikację Django, która pobiera dane Tweeta z interfejsu API serwisu Twitter i zapisuje je w bazie danych MySQL. O ile wiem (wciąż mam głowę dookoła lepszych punktów kodowania znaków) używam UTF-8 wszędzie, włączając w to kodowanie i sortowanie MySQL, co działa dobrze, z wyjątkiem sytuacji, gdy tweet zawiera znaki Emoji, które Rozumiem, że używam czterobajtowego kodowania. Próbuje je zapisać produkuje następujące ostrzeżenia od Django:Jak mogę filtrować znaki Emoji z mojego wejścia, aby zapisać w MySQL <5.5?

/home/biggleszx/.virtualenvs/myvirtualenv/lib/python2.6/site-packages/django/db/backends/mysql/base.py:86 : Ostrzeżenie: Nieprawidłowa wartość ciąg: '\ xF0 \ x9F \ x98 \ XAD I ...' w kolumnie 'tekst' w wierszu 1 self.cursor.execute powrotnej (zapytania, args)

jestem przy użyciu MySQL 5.1, więc używanie utf8mb4 nie jest opcją, chyba że uaktualniam do wersji 5.5, co raczej nie chciałbym jeszcze (także z tego, co przeczytałem, wsparcie Django dla tego nie jest gotowe do produkcji, choć może to nie są już dokładne). Widziałem także folks doradzając użycie BLOB zamiast TEKSTU na zaatakowanych kolumnach, co też wolałbym nie robić, ponieważ sądzę, że może to zaszkodzić wydajności.

Moje pytanie brzmi, zakładając, że nie przejmuję się w 100% zachowywaniem zawartości tweetów, czy istnieje sposób na odfiltrowanie wszystkich znaków Emoji i zastąpienie ich postacią inną niż wielobajtowa, na przykład czcigodny WHITE MEDIUM SMALL SQUARE (U+25FD)? Sądzę, że jest to najłatwiejszy sposób na zapisanie tych danych, biorąc pod uwagę moją obecną konfigurację, ale jeśli brakuje mi innego oczywistego rozwiązania, chciałbym to usłyszeć!

FYI, używam wersji Python 2.6.5 na Ubuntu 10.04.4 LTS. sys.maxunicode to 1114111, więc jest to kompilacja UCS-4.

Dzięki za przeczytanie.

+0

UTF8 może kodować nie- Znaki BMP: – SLaks

+3

@SLaks: Tak, ale zestaw znaków MySQL 'utf8' nie może ich zapisać, ponieważ używa tylko 3 bajtów. –

Odpowiedz

21

Okazuje się, że odpowiedź została udzielona kilka razy, po prostu nie miałem odpowiedniego Google-fu, aby znaleźć istniejące pytania.

Dzięki Martijn Pieters, rozwiązanie przyszedł ze świata wyrażeń regularnych, a konkretnie tego kodu (na podstawie jego odpowiedzi na pierwsze linku powyżej):

import re 
try: 
    # UCS-4 
    highpoints = re.compile(u'[\U00010000-\U0010ffff]') 
except re.error: 
    # UCS-2 
    highpoints = re.compile(u'[\uD800-\uDBFF][\uDC00-\uDFFF]') 
# mytext = u'<some string containing 4-byte chars>' 
mytext = highpoints.sub(u'\u25FD', mytext) 

Postać, którą wymieniam, to WHITE MEDIUM SMALL SQUARE (U+25FD), FYI, ale może być dowolna.

Dla osób niezaznajomionych z UCS, takich jak ja, jest to system do konwersji Unicode, a dana wersja Pythona będzie zawierać obsługę wariantu UCS-2 lub UCS-4, z których każdy ma inną górną granicę na wsparcie dla postaci.

Po dodaniu tego kodu, ciągi wydają się utrzymywać w MySQL 5.1.

Mam nadzieję, że pomoże to każdemu innemu w tej samej sytuacji!

13

Próbowałem rozwiązania BigglesZX i jego nie nudziłem się za emoji serca (❤) po przeczytaniu [artykułu wikipedia emoji] [1] Widziałem, że wyrażenie regularne nie obejmuje wszystkich emotikonów jednocześnie obejmując inny zakres unicode, które nie są emoji.

Następujący kod tworzyć 5 wyrażenia regularne zakrywającą 5 emoji bloków normy:

emoji_symbols_pictograms = re.compile(u'[\U0001f300-\U0001f5fF]') 
emoji_emoticons = re.compile(u'[\U0001f600-\U0001f64F]') 
emoji_transport_maps = re.compile(u'[\U0001f680-\U0001f6FF]') 
emoji_symbols = re.compile(u'[\U00002600-\U000026FF]') 
emoji_dingbats = re.compile(u'[\U00002700-\U000027BF]') 

te bloki mogą być połączone w trzech bloków (UCS-4):

emoji_block0 = re.compile(u'[\U00002600-\U000027BF]') 
emoji_block1 = re.compile(u'[\U0001f300-\U0001f64F]') 
emoji_block2 = re.compile(u'[\U0001f680-\U0001f6FF]') 

Ich odpowiednikami w UCS-2 są:

emoji_block0 = re.compile(u'[\u2600-\u27BF]') 
emoji_block1 = compile(u'[\uD83C][\uDF00-\uDFFF]') 
emoji_block1b = compile(u'[\uD83D][\uDC00-\uDE4F]') 
emoji_block2 = re.compile(u'[\uD83D][\uDE80-\uDEFF]') 

W końcu możemy zdefiniować pojedynczy regularny e xpression ze wszystkimi przypadkami razem:

import re 
try: 
    # UCS-4 
    highpoints = re.compile(u'([\U00002600-\U000027BF])|([\U0001f300-\U0001f64F])|([\U0001f680-\U0001f6FF])') 
except re.error: 
    # UCS-2 
    highpoints = re.compile(u'([\u2600-\u27BF])|([\uD83C][\uDF00-\uDFFF])|([\uD83D][\uDC00-\uDE4F])|([\uD83D][\uDE80-\uDEFF])') 
# mytext = u'<some string containing 4-byte chars>' 
mytext = highpoints.sub(u'\u25FD', mytext) 
0

Dowiedziałem się o innej regularnej ekspresji, która jest w stanie zidentyfikować emoji. Ten regex jest przez zespół w Instagram-enginnering blogu

u"(?<!&)#(\w|(?:[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u2388\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267B\u267F\u2692-\u2694\u2696\u2697\u2699\u269B\u269C\u26A0\u26A1\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD79\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED0\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3]|\uD83E[\uDD10-\uDD18\uDD80-\uDD84\uDDC0]|(?:0\u20E3|1\u20E3|2\u20E3|3\u20E3|4\u20E3|5\u20E3|6\u20E3|7\u20E3|8\u20E3|9\u20E3|#\u20E3|\\*\u20E3|\uD83C(?:\uDDE6\uD83C(?:\uDDEB|\uDDFD|\uDDF1|\uDDF8|\uDDE9|\uDDF4|\uDDEE|\uDDF6|\uDDEC|\uDDF7|\uDDF2|\uDDFC|\uDDE8|\uDDFA|\uDDF9|\uDDFF|\uDDEA)|\uDDE7\uD83C(?:\uDDF8|\uDDED|\uDDE9|\uDDE7|\uDDFE|\uDDEA|\uDDFF|\uDDEF|\uDDF2|\uDDF9|\uDDF4|\uDDE6|\uDDFC|\uDDFB|\uDDF7|\uDDF3|\uDDEC|\uDDEB|\uDDEE|\uDDF6|\uDDF1)|\uDDE8\uD83C(?:\uDDF2|\uDDE6|\uDDFB|\uDDEB|\uDDF1|\uDDF3|\uDDFD|\uDDF5|\uDDE8|\uDDF4|\uDDEC|\uDDE9|\uDDF0|\uDDF7|\uDDEE|\uDDFA|\uDDFC|\uDDFE|\uDDFF|\uDDED)|\uDDE9\uD83C(?:\uDDFF|\uDDF0|\uDDEC|\uDDEF|\uDDF2|\uDDF4|\uDDEA)|\uDDEA\uD83C(?:\uDDE6|\uDDE8|\uDDEC|\uDDF7|\uDDEA|\uDDF9|\uDDFA|\uDDF8|\uDDED)|\uDDEB\uD83C(?:\uDDF0|\uDDF4|\uDDEF|\uDDEE|\uDDF7|\uDDF2)|\uDDEC\uD83C(?:\uDDF6|\uDDEB|\uDDE6|\uDDF2|\uDDEA|\uDDED|\uDDEE|\uDDF7|\uDDF1|\uDDE9|\uDDF5|\uDDFA|\uDDF9|\uDDEC|\uDDF3|\uDDFC|\uDDFE|\uDDF8|\uDDE7)|\uDDED\uD83C(?:\uDDF7|\uDDF9|\uDDF2|\uDDF3|\uDDF0|\uDDFA)|\uDDEE\uD83C(?:\uDDF4|\uDDE8|\uDDF8|\uDDF3|\uDDE9|\uDDF7|\uDDF6|\uDDEA|\uDDF2|\uDDF1|\uDDF9)|\uDDEF\uD83C(?:\uDDF2|\uDDF5|\uDDEA|\uDDF4)|\uDDF0\uD83C(?:\uDDED|\uDDFE|\uDDF2|\uDDFF|\uDDEA|\uDDEE|\uDDFC|\uDDEC|\uDDF5|\uDDF7|\uDDF3)|\uDDF1\uD83C(?:\uDDE6|\uDDFB|\uDDE7|\uDDF8|\uDDF7|\uDDFE|\uDDEE|\uDDF9|\uDDFA|\uDDF0|\uDDE8)|\uDDF2\uD83C(?:\uDDF4|\uDDF0|\uDDEC|\uDDFC|\uDDFE|\uDDFB|\uDDF1|\uDDF9|\uDDED|\uDDF6|\uDDF7|\uDDFA|\uDDFD|\uDDE9|\uDDE8|\uDDF3|\uDDEA|\uDDF8|\uDDE6|\uDDFF|\uDDF2|\uDDF5|\uDDEB)|\uDDF3\uD83C(?:\uDDE6|\uDDF7|\uDDF5|\uDDF1|\uDDE8|\uDDFF|\uDDEE|\uDDEA|\uDDEC|\uDDFA|\uDDEB|\uDDF4)|\uDDF4\uD83C\uDDF2|\uDDF5\uD83C(?:\uDDEB|\uDDF0|\uDDFC|\uDDF8|\uDDE6|\uDDEC|\uDDFE|\uDDEA|\uDDED|\uDDF3|\uDDF1|\uDDF9|\uDDF7|\uDDF2)|\uDDF6\uD83C\uDDE6|\uDDF7\uD83C(?:\uDDEA|\uDDF4|\uDDFA|\uDDFC|\uDDF8)|\uDDF8\uD83C(?:\uDDFB|\uDDF2|\uDDF9|\uDDE6|\uDDF3|\uDDE8|\uDDF1|\uDDEC|\uDDFD|\uDDF0|\uDDEE|\uDDE7|\uDDF4|\uDDF8|\uDDED|\uDDE9|\uDDF7|\uDDEF|\uDDFF|\uDDEA|\uDDFE)|\uDDF9\uD83C(?:\uDDE9|\uDDEB|\uDDFC|\uDDEF|\uDDFF|\uDDED|\uDDF1|\uDDEC|\uDDF0|\uDDF4|\uDDF9|\uDDE6|\uDDF3|\uDDF7|\uDDF2|\uDDE8|\uDDFB)|\uDDFA\uD83C(?:\uDDEC|\uDDE6|\uDDF8|\uDDFE|\uDDF2|\uDDFF)|\uDDFB\uD83C(?:\uDDEC|\uDDE8|\uDDEE|\uDDFA|\uDDE6|\uDDEA|\uDDF3)|\uDDFC\uD83C(?:\uDDF8|\uDDEB)|\uDDFD\uD83C\uDDF0|\uDDFE\uD83C(?:\uDDF9|\uDDEA)|\uDDFF\uD83C(?:\uDDE6|\uDDF2|\uDDFC))))[\ufe00-\ufe0f\u200d]?)+ 

Źródło: http://instagram-engineering.tumblr.com/post/118304328152/emojineering-part-2-implementing-hashtag-emoji

uwaga: dodam kolejną odpowiedź, to nie jest complemetary do mojej poprzedniej odpowiedzi tutaj.

0

Używam funkcji enkodera json, która koduje dane wejściowe.

ta funkcja służy do kodowania dyktafonu (w celu przekształcenia go w ciąg znaków) w json.dumps. (Tak musimy zrobić trochę zmienił się z odpowiedzią - usuń ' "„)

to pozwoliło mi zaoszczędzić emotikony do mysql, i przedstawić go (w internecie):

# encode input 
from json.encoder import py_encode_basestring_ascii 
name = py_encode_basestring_ascii(name)[1:-1] 

# save 
YourModel.name = name 
name.save() 
Powiązane problemy