Заменить серию символов Юникода / Python / Twitter

Я беру текст из твита с помощью Twitter API и Python 3.3, и я сталкиваюсь с той частью твита, где твитер помещает в твит три символа. Они показаны ниже. Два флажка и большой палец вверх

Кажется, проблема связана с двумя флажками и поднятием большого пальца. Ниже приводится текстовый твит.

RT @John_Hunt07: Just voted for @marcorubio is Florida! I am ready for a New American Century!! #FLPrimary \ud83c\uddfa\ud83c\uddf8\ud83c\uddfa\ud83c\uddf8\ud83d\udc4d

Ниже приведен код, который я использую.

import json
import mysql.connector
import sys
from datetime import datetime
from MySQLCL import MySQLCL

class Functions(object):
"""This is a class for Python functions"""

@staticmethod
def Clean(string):
    temp = str(string)
    temp = temp.replace("'", "").replace("(", "").replace(")", "").replace(",", "").strip()
    return temp

@staticmethod
def ParseTweet(string):
    for x in range(0, len(string)):
        tweetid = string[x]["id_str"]
        tweetcreated = string[x]["created_at"]
        tweettext = string[x]["text"]
        tweetsource = string[x]["source"]
        tweetsource = tweetsource
        truncated = string[x]["truncated"]
        inreplytostatusid = string[x]["in_reply_to_status_id"]
        inreplytouserid = string[x]["in_reply_to_user_id"]
        inreplytoscreenname = string[x]["in_reply_to_screen_name"]
        geo = string[x]["geo"]
        coordinates = string[x]["coordinates"]
        place = string[x]["place"]
        contributors = string[x]["contributors"]
        isquotestatus = string[x]["is_quote_status"]
        retweetcount = string[x]["retweet_count"]
        favoritecount = string[x]["favorite_count"]
        favorited = string[x]["favorited"]
        retweeted = string[x]["retweeted"]
        if "possibly_sensitive" in string[x]:
            possiblysensitive = string[x]["possibly_sensitive"]
        else:
            possiblysensitive = ""
        language = string[x]["lang"]

        #print(possiblysensitive)
        print(Functions.UnicodeFilter(tweettext))
        #print(inreplytouserid)
        #print("INSERT INTO tweet(ExTweetID, TweetText, Truncated, InReplyToStatusID, InReplyToUserID, InReplyToScreenName, IsQuoteStatus, RetweetCount, FavoriteCount, Favorited, Retweeted, Language, TweetDate, TweetSource, PossiblySensitive) VALUES (" + str(tweetid) + ", '" + Functions.UnicodeFilter(tweettext) + "', " + str(truncated) + ", " + Functions.CheckNull(inreplytostatusid) + ", " + Functions.CheckNull(inreplytouserid) + ", '" + Functions.CheckNull(inreplytoscreenname) + "', " + str(isquotestatus) + ", " + str(retweetcount) + ", " + str(favoritecount) + ", " + str(favorited) + ", " + str(retweeted) + ", '" + str(language) + "', '" + Functions.ToSQL(tweetcreated) + "', '" + Functions.ToSQL(tweetsource) + "', " + str(possiblysensitive) + ")")
        #MySQLCL.Set("INSERT INTO tweet(ExTweetID, TweetText, Truncated, InReplyToStatusID, InReplyToUserID, InReplyToScreenName, IsQuoteStatus, RetweetCount, FavoriteCount, Favorited, Retweeted, Language, TweetDate, TweetSource, PossiblySensitive) VALUES (" + str(tweetid) + ", '" + tweettext + "', " + str(truncated) + ", " + Functions.CheckNullNum(inreplytostatusid) + ", " + Functions.CheckNullNum(inreplytouserid) + ", '" + Functions.CheckNull(inreplytoscreenname) + "', " + str(isquotestatus) + ", " + str(retweetcount) + ", " + str(favoritecount) + ", " + str(favorited) + ", " + str(retweeted) + ", '" + language + "', '" + str(Functions.FormatDate(tweetcreated)) + "', '" + str(Functions.UnicodeFilter(tweetsource)) + "', " + str(possiblysensitive) + ")")

@staticmethod
def ToBool(variable):
    if variable.lower() == 'true':
        return True
    elif variable.lower() == 'false':
        return False

@staticmethod
def CheckNullNum(var):
    if var == None:
        return "0"
    else:
        return str(var)

@staticmethod
def CheckNull(var):
    if var == None:
        return ""
    else:
        return var

@staticmethod
def ToSQL(var):
    temp = var
    temp = temp.replace("'", "")
    return str(temp)

@staticmethod
def UnicodeFilter(var):
    temp = var
    temp = temp.replace(chr(0x2019), "")
    temp = temp.replace(chr(0x003c), "(lessthan)")
    temp = temp.replace(chr(0x003e), "(greaterthan)")
    temp = temp.replace(chr(0xd83c), "")
    temp = temp.replace(chr(0xddfa), "")
    temp = temp.replace(chr(0xddf8), "")
    temp = temp.replace(chr(0xd83d), "")
    temp = temp.replace(chr(0xdc4d), "")
    temp = Functions.ToSQL(temp)
    return temp

@staticmethod
def FormatDate(var):
    temp = var
    dt = datetime.strptime(temp, "%a %b %d %H:%M:%S %z %Y")
    retdt = str(dt.year) + "-" + str(dt.month) + "-" + str(dt.day) + "T" + str(dt.hour) + ":" + str(dt.minute) + ":" + str(dt.second)
    return retdt

Как видите, я использовал функцию UnicodeFilter, чтобы попытаться отфильтровать символы Юникода в шестнадцатеричном формате. Функция работает при работе с отдельными символами Юникода, но при обнаружении нескольких символов Юникода, помещенных вместе, этот метод не работает и выдает следующую ошибку:

Кодек 'charmap' не может кодировать символы в позиции 107-111: символы отображаются в 'undefined'

Есть ли у кого-нибудь из вас идеи, как решить эту проблему?

ОБНОВЛЕНИЕ: я пробовал решение Эндрю Годбеера, и у меня все еще возникали те же проблемы. Однако я решил проверить, есть ли какие-либо конкретные символы, вызывающие проблему, поэтому я решил выводить символы на консоль символ за символом. Это дало мне следующую ошибку:

Кодек 'charmap' не может кодировать символ '\ U0001f1fa' в позиции 0: символ отображается в 'undefined'

Увидев это, я добавил это в функцию UnicodeFilter и продолжил тестирование. Я столкнулся с несколькими ошибками одного и того же типа при печати твитов посимвольно. Однако я не хочу продолжать делать эти исключения. Например, см. Обновленную функцию UnicodeFilter:

@staticmethod
def UnicodeFilter(var):
    temp = var
    temp = temp.encode(errors='ignore').decode('utf-8')
    temp = temp.replace(chr(0x2019), "")
    temp = temp.replace(chr(0x003c), "(lessthan)")
    temp = temp.replace(chr(0x003e), "(greaterthan)")
    temp = temp.replace(chr(0xd83c), "")
    temp = temp.replace(chr(0xddfa), "")
    temp = temp.replace(chr(0xddf8), "")
    temp = temp.replace(chr(0xd83d), "")
    temp = temp.replace(chr(0xdc4d), "")
    temp = temp.replace(chr(0x2026), "")
    temp = temp.replace(u"\U0001F1FA", "")
    temp = temp.replace(u"\U0001F1F8", "")
    temp = temp.replace(u"\U0001F44D", "")
    temp = temp.replace(u"\U00014F18", "")
    temp = temp.replace(u"\U0001F418", "")
    temp = temp.replace(u"\U0001F918", "")
    temp = temp.replace(u"\U0001F3FD", "")
    temp = temp.replace(u"\U0001F195", "")
    temp = Functions.ToSQL(temp)
    return str(temp)

Я не хочу добавлять новую строку для каждого символа, вызывающего проблему. С помощью этого метода мне удалось передать несколько твитов, но эта проблема возникает с каждым твитом, содержащим разные символы. Разве нет решения, которое отфильтрует всех этих персонажей? Можно ли отфильтровать все символы, не входящие в набор символов utf-8?


person TheRedCameron    schedule 23.03.2016    source источник


Ответы (3)


Попробуйте встроенную функцию обработки ошибок кодирования / декодирования Unicode: str.encode(errors='ignore')

Например:

problem_string = """\
RT @John_Hunt07: Just voted for @marcorubio is Florida! I am ready for a New American Century!! #FLPrimary \ud83c\uddfa\ud83c\uddf8\ud83c\uddfa\ud83c\uddf8\ud83d\udc4d
"""
print(problem_string.encode(errors='ignore').decode('utf-8'))

Игнорирование ошибок удаляет проблемные символы.

> RT @John_Hunt07: Just voted for @marcorubio is Florida! I am ready for a New American Century!! #FLPrimary 

Могут быть интересны другие варианты обработки ошибок. xmlcharrefreplace, например, даст:

> RT @John_Hunt07: Just voted for @marcorubio is Florida! I am ready for a New American Century!! #FLPrimary ����������

Если вам требуется настраиваемая фильтрация, как подразумевается вашей функцией UnicodeFilter, см. документацию Python по регистрации обработчик ошибок.

person Andrew Godbehere    schedule 23.03.2016
comment
@theredcameron Ваша проблема может быть связана с консолью Windows, как описано в другой пост. - person Andrew Godbehere; 24.03.2016

Нашел ответ. Проблема заключалась в том, что в твитах был ряд персонажей, которые вызывали проблемы. Как только я нашел правильный диапазон Unicode для символов, я реализовал цикл for для замены любого вхождения любого символа Unicode в этом диапазоне. После реализации этого я смог вытащить тысячи твитов без какого-либо форматирования или ошибок MySQL.

@staticmethod
def UnicodeFilter(var):
    temp = var
    temp = temp.replace(chr(0x2019), "'")
    temp = temp.replace(chr(0x2026), "")
    for x in range(127381, 129305):
        temp = temp.replace(chr(x), "")
    temp = MySQLCL.ToSQL(temp)
    return str(temp)
person TheRedCameron    schedule 15.06.2016

Python предоставляет полезную трассировку стека, чтобы вы могли определить, откуда берутся ошибки. Используя его, вы обнаружите, что ваш print вызывает исключение.

print() не работает, потому что вы запускаете Python из консоли Windows, которая только по умолчанию поддерживает вашу локальную 8-битную карту символов. Вы можете добавить поддержку с помощью: https://github.com/Drekin/win-unicode-console

Вы также можете просто записать свои данные прямо в текстовый файл. Откройте файл с помощью:

open('output.txt', 'w', encoding='utf-8')
person Alastair McCormack    schedule 24.03.2016