Функция maketrans() Python 2 не работает с Unicode: аргументы имеют разную длину, когда они на самом деле

[Python 2] SUB = string.maketrans("0123456789","₀₁₂₃₄₅₆₇₈₉")

этот код выдает ошибку:

ValueError: maketrans arguments must have same length

Я не уверен, почему это происходит, потому что строки имеют одинаковую длину. Моя единственная идея заключается в том, что длина текста нижнего индекса как-то отличается от символов стандартного размера, но я не знаю, как это обойти.


person Aaron    schedule 07.05.2015    source источник
comment
Отлично работает в Python 3 (который в любом случае имеет гораздо лучшую поддержку юникода), это вариант для вас?   -  person Stefan Pochmann    schedule 07.05.2015
comment
в настоящее время я использую Python 2.7, но я обязательно посмотрю на Python 3.   -  person Aaron    schedule 07.05.2015
comment
Этот код Python 3 взят из аккуратного ответа @ZeroPiraeus на Печать нижнего индекса в python   -  person smci    schedule 10.09.2018


Ответы (1)


Нет, аргументы не одинаковой длины:

>>> len("0123456789")
10
>>> len("₀₁₂₃₄₅₆₇₈₉")
30

Вы пытаетесь передать закодированные данные; Здесь я использовал UTF-8, где каждая цифра кодируется по 3 байта.

Вы не можете использовать str.translate() для сопоставления байтов ASCII с последовательностями байтов UTF-8. Декодируйте вашу строку в unicode и используйте немного другой метод unicode.translate(); вместо этого используется словарь:

nummap = {ord(c): ord(t) for c, t in zip(u"0123456789", u"₀₁₂₃₄₅₆₇₈₉")}

Это создает словарь, отображающий кодовые точки Unicode (целые числа), которые затем можно использовать в строке Unicode:

>>> nummap = {ord(c): ord(t) for c, t in zip(u"0123456789", u"₀₁₂₃₄₅₆₇₈₉")}
>>> u'99 bottles of beer on the wall'.translate(nummap)
u'\u2089\u2089 bottles of beer on the wall'
>>> print u'99 bottles of beer on the wall'.translate(nummap)
₉₉ bottles of beer on the wall

Затем вы можете снова закодировать вывод в UTF-8, если хотите.

Из документации по методу:

Для объектов Unicode метод translate() не принимает необязательный аргумент deletechars. Вместо этого он возвращает копию s, в которой все символы были сопоставлены через данную таблицу перевода, которая должна быть сопоставлением порядковых номеров Unicode с порядковыми номерами Unicode, строками Unicode или None. Несопоставленные символы остаются нетронутыми. Символы, сопоставленные с None, удаляются.

person Martijn Pieters    schedule 07.05.2015
comment
есть ли другой способ получить символы нижнего индекса в python? или даже способ преодолеть эту разницу в длине - person Aaron; 07.05.2015
comment
Аарон: это не было бы ограничением Python... скорее это следствие различий между ASCII и Unicode. В ASCII нет символов нижнего индекса. Последствия использования символов Unicode заключаются в том, что Python не может обрабатывать такие символы, как если бы они были ASCII --- любая попытка сделать это может работать в одних случаях, но не работает в других. - person Jim Dennis; 07.05.2015
comment
@Martijn Где ты взял 30? Я получаю либо 10, либо неподдерживаемые символы на входе, в зависимости от того, где я пытаюсь это сделать. - person Stefan Pochmann; 07.05.2015
comment
@StefanPochmann: использование интерактивного интерпретатора в терминале, настроенном для использования UTF-8. - person Martijn Pieters; 07.05.2015
comment
Только в Python 2. Длина 30 в Python 2 и 10 в Python 3. Код OP отлично работает в Python 3. - person smci; 10.09.2018
comment
@smci точно; вы увидите эту конкретную ошибку только в Python 2, потому что это строки байтов. Вот почему вопрос помечен тегом python-2.x. - person Martijn Pieters; 10.09.2018