Нормализовать стандарта GSM короткие текстовые сообщения


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

import logging
import traceback
import unicodedata
logger = logging.getLogger(__name__)

class IsGSM:

    def __init__(self):
        self.gsm = "@£$¥èéùìòÇ\nØø\rÅåΔ_ΦΓΛΩΠΨΣΘΞ\x1bÆæßÉ !\"#¤%&'()*+,-./0123456789:;<=>?" \
      "¡ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÑܧ¿abcdefghijklmnopqrstuvwxyzäöñüà"
        self.ext = "^{}\\[~]|€"
        self.toBeNormalized = '\xa0'+'\xc2'
        self.ascii_gsm = {}
        self.ascii_map()
        self.normalize_dict = {}
        self.normalize_map()

    def ascii_map(self):
        for c in self.gsm:
            #if ord(c) < 256:
            self.ascii_gsm[ord(c)] = True
        for c in self.ext:
            #if ord(c) < 256:
            self.ascii_gsm[ord(c)] = True

    def normalize_map(self):
        for c in self.toBeNormalized:
            self.normalize_dict[c] = True

    def _is_gsm(self, content):

        template = content

        try:
            template.encode('windows-1252')
        except UnicodeEncodeError:
            return False

        for c in content:
            if ord(c) not in self.ascii_gsm:
                return False
        return True

    @classmethod
    def is_gsm(cls, content):
        instance = IsGSM.instance()
        return instance._is_gsm(content)

    @classmethod
    def normalizeBodyContent(cls, content):
        instance = IsGSM.instance()
        return instance._normalizeBodyContent(content)

    @classmethod
    def instance(cls):
        """Singleton like accessor to instantiate backend object"""
        if not hasattr(cls, "_instance"):
            cls._instance = cls()
        return cls._instance

    def _normalizeBodyContent(self, content):
        try:
            target_content = [c for c in content]
            content_length = len(target_content)
            for ith in range(content_length):
                if target_content[ith] in self.normalize_dict:
                    target_content[ith] = unicodedata.normalize("NFKD",target_content[ith])

            content = "".join(target_content)
        except Exception as e:
               logger.error('Exception occurred normalizing content {0}'.format(content))
               traceback.print_exc()
               raise e
        return content

if __name__ == "__main__":
    print(IsGSM.is_gsm("Est a punto de restablecer la contrasea de su cartera de Kutxabank. Por favor, introduzca la sigui..."))
    print(IsGSM.is_gsm("This should fix the problem. Your content xxxxx from ÄA K COMPANY LTD will be delivered by xxxx today.Track your content at  some_url@&!"))

Я могу рефакторинг _normalizeBodyContent способ такой:

def _normalizeBodyContent(self, content):
    try:
        target_content = [c for c in content]
        content_length = len(target_content)
        for ith in self.normalize_dict:
            target_content = target_content.replace(ith,
                                         unicodedata.normalize("NFKD", ith))
        content = "".join(target_content)
    except Exception as e:
        logger.error('Exception occurred normalizing content {0}'.format(content))
        traceback.print_exc()
        raise e
    return content

Это лучше оригинала, в плане времени обработки и читабельности?

Я особенно заинтересован в сравнении поиска через in и переписать с помощью replace() библиотека функции. Комментарий на любую часть всего сценария тоже оценили.



Комментарии
1 ответ

1. Комментарий


  1. Как правило, класс используется для реализации сбора объектов с аналогичными поведения, и объект используется для реализации какой-то настойчивый вещь или структуры данных. Но какая вещь является экземпляром IsGsm класса? Это не выглядит так, как будто она соответствует какой-либо вещи.

    То, что вы действительно здесь-это функция (IsGsm.is_gsm), что определяет, будет ли текст может быть закодирован в GSM 03.38. Понятно, что это функция, а не метод, потому что он не использует его cls аргумент. Так было бы понятнее и проще если бы это была функция. В Python, не все должно быть частью класса!

    Смотрите Джек Diederichбыл говорить "перестаньте писать классы" для подробнее об этой проблеме.


  2. Новый ascii_gsm структура данных выстраивается каждый раз, когда вы называете IsGsm.is_gsmно каждый раз, когда структура данных одинакова. Было бы проще если бы это была глобальная переменная. Тогда он был бы когда-то построил.

  3. В ascii_gsm структура данных-это плохо назвал: это сопоставление, чьи ключи в кодировке Unicode кодовые точки для символов, которые можно закодировать.

  4. Значения ascii_gsm структура данных всегда True. Это пустая трата пространства: Если вам просто нужны ключи, то Python имеет набор данных.

  5. Код в Post считает, что форма подачи не может быть закодирована:

    >>> IsGSM.is_gsm('\N{FORM FEED}')
    False

    но в соответствии с "основным набором символов расширения" таблица в Википедии, форма подачи может быть закодирован как два байта 1Б 0А.


  6. Я думаю, что было бы понятнее и менее рискованно использовать в Python Юникод имени убегает, и писать \N{ESCAPE} вместо \x1b. Экс-легче читать, легче проверить, и Python выдает ошибку, если вы сделаете опечатку:

    >>> '\N{ESACPE}'
    File "<stdin>", line 1
    SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 0-9: unknown Unicode character name

    С шестнадцатеричными убегает, питон не поможет вам, если вы напишите \x1c по ошибке для \x1b.


  7. Но деться действительно быть закодированы как 7-битовые сети GSM? Она смотрит на меня, как будто он не может — в Википедии написано:


    Обратите внимание, что вторая часть таблицы доступен только если устройство gsm и поддерживает 7-битный механизм, используя префикс символа Esc. В противном случае, сам код ЭКУ интерпретируется как пробел и следующий символ будет рассматриваться как если бы не было ведущих код Esc.

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


  8. Непонятно, почему вы хотите нормализовать \xc2. Это прописная латинская буква A с ЦИРКУМФЛЕКСОМ, и когда нормализуется как NFKD это становится буквой алфавита, с последующим суммированием облеченным ударением. Но сочетание облеченным ударением не могут быть закодированы как 7-битовые GSM, так нормализация не поможет. Я думаю, что это нуждается в пояснении, или возможно только удаление.

2. Пересмотренный кодекс

Я думаю, что было бы больше смысла, чтобы построить кодек. Идея в том, чтобы написать encode функция, которая кодирует текст Юникод как 7-битного стандарта GSM, используя тот же интерфейс, как в Python собственного codecs.encode. Тогда абоненты будут иметь возможность писать такой код для определения текста, которая не может быть закодирована, используя "жесткие" ошибки дрессировщика:

try:
gsm_encoded_bytes = encode(text, 'strict')
except UnicodeEncodeError:
# Can't encode text as GSM

Этот интерфейс поддерживает более изящной обработки ошибок, например, если "заменить" обработчик ошибок , то на выходе 3Ф, когда символ не может быть закодирован:

>>> encode('abcω', 'replace')
b'abc?'

Вот такой старт на реализацию:

import codecs

# Name of the codec.
_NAME = 'gsm03.38'

# GSM 03.38 Basic Character Set
_BASIC_CHARACTERS = (
"@£$¥èéùìòÇ\nØø\rÅåΔ_ΦΓΛΩΠΨΣΘΞ\N{ESCAPE}ÆæßÉ"
" !\"#¤%&'()*+,-./0123456789:;<=>?"
"¡ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÑܧ"
"¿abcdefghijklmnopqrstuvwxyzäöñüà")

# GSM 03.38 Basic Character Set Extension. Note that CR2 and SS2 are
# not Unicode characters, so don't appear in this table.
_EXTENSION_CHARACTERS = {
'\N{FORM FEED}': 0x0A,
'^': 0x14,
'{': 0x28,
'}': 0x29,
'\\': 0x2F,
'[': 0x3C,
'~': 0x3D,
']': 0x3E,
'|': 0x40,
'€': 0x65,
}

# These are not in the GSM 03.38 specification but we provide them for
# convenience.
_ADDITIONAL_CHARACTERS = {
'\N{NO-BREAK SPACE}': 0x20,
}

# Build mapping from Unicode character to GSM 03.38 encoding
_CHARMAP = {c: bytes([i]) for i, c in enumerate(_BASIC_CHARACTERS)}
del _CHARMAP['\N{ESCAPE}']
for char, encoding in _EXTENSION_CHARACTERS.items():
_CHARMAP[char] = bytes([0x1B, encoding])
for char, encoding in _ADDITIONAL_CHARACTERS.items():
_CHARMAP[char] = bytes([encoding])

def encode(input, errors='strict'):
error_handler = codecs.lookup_error(errors)
result = bytearray()
i = 0
while i < len(input):
c = input[i]
if c in _CHARMAP:
result.extend(_CHARMAP[c])
i += 1
else:
exc = UnicodeEncodeError(_NAME, input, i, i + 1, "no encoding")
replace, i = error_handler(exc)
for c in replace:
result.extend(_CHARMAP[c])
return bytes(result)

С немного больше работы, мы могли бы добавить decode функция, которая декодирует 7-битного стандарта GSM в Юникоде, используя тот же интерфейс, как и в Python собственного codecs.decode функция. Тогда мы сможем зарегистрировать наши функции с кодеком реестра, позволяя пользователям писать код вроде:

try:
gsm_encoded_bytes = text.encode('gsm03.38', 'strict')
except UnicodeEncodeError:
# Can't encode text as GSM

Но на самом деле уже существует в GSM 03.38 кодек на языке Python пакет индекса, и, вероятно, имеет смысл использовать, что вместо того, чтобы писать свои собственные.

4
ответ дан 2 февраля 2018 в 05:02 Источник Поделиться