Декодировать японские символы в Base64 - PullRequest
0 голосов
/ 25 апреля 2019

У меня есть немного сложная проблема с декодированием ... У меня есть код, который берет заметки из gmail (взятые siri), вставляет их в переменную и сравнивает len слова, чтобы узнать, есть ли слово в keywords список - еще один .py файл

Проблема в том, что gmail меняет японский символ на 6luk, и он не совпадает ... Даже если я изменяю keywords .py file word до 6luk это не работает .... Это работает, только если я напишу это 6luk непосредственно в код.6luk может измениться на , когда я использую

    base64.b64decode(command).decode('utf-8')

, но поскольку он уже выполняет декодирование в

   voice_command = email.message_from_string(data[0][1].decode('utf-8'))

, он не работает хорошо ... Я могудалите этот .decode('utf-8') оттуда, но он не будет работать вообще ... Я попытался декодировать переменную command, содержащую 6luk, из gmail в base64, которая работает в режиме онлайн (декодировать сайты), даже в другой файлс

   base64.b64decode(command).decode('utf-8')

, но он не будет работать в переменной command.Это говорит:

   The word(s) '6luk' have been said
   Received an exception while running: 'utf-8' codec can't decode byte 0xea in position 0: invalid continuation byte

Я искал 0xea, который выглядит как Latin-1, но когда я конвертирую его в Latin-1, он становится еще сложнее: ê[¤

Вот код, который является частью

    hackster.io/thesanjeetc/siricontrol-add-siri-voice-control-to-any-project-644b52

проекта

Кстати.необработанная заметка в gmail выглядит следующим образом


Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: base64
From:  <@gmail.com>
X-Uniform-Type-Identifier: com.apple.mail-note
Mime-Version: 1.0 (iOS/12.2 \(-----\) dataaccessd/1.0)
Date: Thu, 25 Apr 2019 11:42:33 +0900
X-Mail-Created-Date: Thu, 25 Apr 2019 11:42:33 +0900
Subject: 車
X-Universally-Unique-Identifier: --------
Message-Id: <-------@gmail.com>

6LuK


import time
import imaplib
import email
import os
import pkgutil
import base64

##########################################

# Add your gmail username and password here

username = ""
password = ""

##########################################


class ControlException(Exception):
    pass


class Control():
    def __init__(self, username, password):
        print("------------------------------------------------------")
        print("-                    SIRI CONTROL                    -")
        print("-           Created by Sanjeet Chatterjee            -")
        print("-      Website: https://medium.com/@thesanjeetc      -")
        print("------------------------------------------------------")

        try:
            self.last_checked = -1
            self.mail = imaplib.IMAP4_SSL("imap.gmail.com", 993)
            self.mail.login(username, password)
            self.mail.list()
            self.mail.select("Notes")

            # Gets last Note id to stop last command from executing
            result, uidlist = self.mail.search(None, "ALL")
            try:
                self.last_checked = uidlist[0].split()[-1]
            except IndexError:
                pass

            self.load()
            self.handle()
        except imaplib.IMAP4.error:
            print("Your username and password is incorrect")
            print("Or IMAP is not enabled.")

    def load(self):
        """Try to load all modules found in the modules folder"""
        print("\n")
        print("Loading modules...")
        self.modules = []
        path = os.path.join(os.path.dirname(__file__), "modules")
        directory = pkgutil.iter_modules(path=[path])
        for finder, name, ispkg in directory:
            try:
                loader = finder.find_module(name)
                module = loader.load_module(name)
                if hasattr(module, "commandWords") \
                        and hasattr(module, "moduleName") \
                        and hasattr(module, "execute"):
                    self.modules.append(module)
                    print("The module '{0}' has been loaded, "
                          "successfully.".format(name))
                else:
                    print("[ERROR] The module '{0}' is not in the "
                          "correct format.".format(name))
            except:
                print("[ERROR] The module '" + name + "' has some errors.")
        print("\n")

    def fetch_command(self):
        """Retrieve the last Note created if new id found"""
        self.mail.list()
        self.mail.select("Notes")

        result, uidlist = self.mail.search(None, "ALL")
        try:
            latest_email_id = uidlist[0].split()[-1]
        except IndexError:
            return

        if latest_email_id == self.last_checked:
            return

        self.last_checked = latest_email_id
        result, data = self.mail.fetch(latest_email_id, "(RFC822)")
        voice_command = email.message_from_string(data[0][1].decode('utf-8'))
        return str(voice_command.get_payload()).lower().strip()

    def handle(self):
        """Handle new commands

        Poll continuously every second and check for new commands.
        """
        print("Fetching commands...")
        print("\n")

        while True:
            try:
                command = self.fetch_command()
                if not command:
                    raise ControlException("No command found.")

                print("The word(s) '" + command + "' have been said")
                command = base64.b64decode(command)
                command = (command.decode('Latin-1'))
                command = base64.b64encode(command).encode('utf-8')
                command = base64.b64encode(command).decode('utf-8')
                print(command)
                for module in self.modules:
                    foundWords = []
                    for word in module.commandWords:
                        if str(word) in command:
                            foundWords.append(str(word))
                    if len(foundWords) == len(module.commandWords):
                        try:
                            module.execute(command)
                            print("The module {0} has been executed "
                                  "successfully.".format(module.moduleName))
                        except:
                            print("[ERROR] There has been an error "
                                  "when running the {0} module".format(
                                      module.moduleName))
                    else:
                        print("\n")
            except (TypeError, ControlException):
                pass
            except Exception as exc:
                print("Received an exception while running: {exc}".format(
                    **locals()))
                print("Restarting...")
            time.sleep(1)


if __name__ == '__main__':
    Control(username, password)


1 Ответ

2 голосов
/ 25 апреля 2019

Тело, которое вы получаете с помощью imaplib, является bytes объектом.Нет необходимости decode, чтобы передать его в b64decode;

>>> base64.b64decode(b'6Luk')
b'\xe8\xbb\xa4'

Это кодировка UTF-8 символа U + 8ECA , поэтому следующийшаг заключается в том, чтобы декодировать его.

>>> base64.b64decode(b'6Luk').decode('utf-8')
'軤'

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

Без доступа к вашей инфраструктуре я не оченьесть хороший способ проверить это, но это не так, возможно, что-то вроде

    def fetch_command(self):
        """Retrieve the body of the last Note created if new id found"""
        self.mail.list()
        self.mail.select("Notes")

        result, uidlist = self.mail.search(None, "ALL")
        try:
            latest_email_id = uidlist[0].split()[-1]
        except IndexError:
            return

        if latest_email_id == self.last_checked:
            return

        self.last_checked = latest_email_id
        result, data = self.mail.fetch(latest_email_id, "(RFC822)")
        # use message_from_bytes instead of attempting to decode something which almost certainly isn't UTF-8
        note = email.message_from_bytes(data[0][1])
        # extract body part
        voice_command = note.get_payload(decode=True)
        return voice_command.lower().strip()

    def handle(self):
        """Handle new commands

        Poll continuously every second and check for new commands.
        """
        print("Fetching commands...")
        #print("\n")   # empty output lines are an annoyance up with which I will not put

        while True:
            try:
                command = self.fetch_command()
                if not command:
                    raise ControlException("No command found.")

                print("The word(s) '" + command + "' have been said")
                #print(command)
                # etc etc

Если ваш Python достаточно новый (на самом деле 3.3+, но правильно, начиная с версии 3.6, то есть, когда новый API сталпо умолчанию) вы, вероятно, захотите исследовать, используя новые функции библиотеки email с email.policy вместо устаревшего интерфейса.

   from email.policy import default
   # ....
        note = email.message_from_bytes(data[0][1], policy=default)
        voice_command = note.get_body()

Вы заметите, что мы позволяем библиотеке email вычислитьчто декодировать и как.Мы избегаем жесткого кодирования, например, utf-8 или base64, потому что другой фрагмент текста может содержать другой набор символов и / или другую кодировку передачи.Вы должны исследовать и подчиняться заголовкам MIME для каждой отдельной части сообщения.(Мы жестко кодируем ожидание того, что будет одна полезная нагрузка. Я не совсем уверен, что это верное предположение, либо.)

Кстати, это форматирование сообщения не особенноособенность GMail - это то, как MIME инкапсулирует контент, чтобы поддерживать его совместимость с принципиально 7-битным форматом сообщений электронной почты RFC822 только для ASCII.

...