Проблема с .decode ('utf-8'). Upper () и специальными символами (но только внутри строки) - PullRequest
0 голосов
/ 24 февраля 2019

Я хотел бы использовать заглавные буквы в заданной позиции в строке.У меня проблема со специальными буквами - польскими, чтобы быть конкретными: например, «ą».В идеале было бы решение, которое работает также для французского, испанского и т. Д. (Ç, è и т. Д.)

dobry="costąm"
print(dobry[4].decode('utf-8').upper())

Я получаю:

  File "/usr/lib/python2.7/encodings/utf_8.py", line 16, in decode
    return codecs.utf_8_decode(input, errors, True)

UnicodeDecodeError: 'utf8' codec can't decode byte 0xc4 in position 0: unexpected end of data

, а для этого:

print("ą".decode('utf-8').upper())

Я получаю Ą по желанию.

Что более любопытно для букв на позициях 0-3, это нормально работает, в то время как для:

print(dobry[5].decode('utf-8').upper())

У меня та же проблема

Ответы [ 3 ]

0 голосов
/ 24 февраля 2019

что об этом вместо:

print(dobry.decode('utf-8')[5].upper())
0 голосов
/ 24 февраля 2019

UTF-8 может использовать более одного байта для кодирования символа, поэтому итерация по байтовой строке и манипулирование отдельными байтами не всегда будут работать.Лучше декодировать в Python 2 unicode type.Выполните ваши манипуляции, а затем перекодируйте в UTF-8.

>>> dobry="costąm"
>>> udobry = unicode(dobry, 'utf-8')
>>> changed = udobry[:4] + udobry[4].upper() + udobry[5]
>>> new_dobry = changed.encode('utf-8')
>>> print new_dobry
costĄm

Как прокомментировал @tripleee, не-ascii символы могут не отображаться в одну кодовую точку Юникода: «ą» может быть единственной кодовой точкой U +0105 МАЛЕНЬКОЕ ЛАТИНСКОЕ ПИСЬМО А С ОГОНЕКОМ или оно может быть составлено из «а», за которым следует U + 0328 КОМБИНИРОВАНИЕ ОГОНЕКА.

В составленной строке символ «a» может быть заглавным, а «a», за которым следует КОМБИНИРОВАНИЕ OGONEK, приведет к «Ą» (хотя это может выглядеть как два отдельных символа в Python REPL или терминале(в зависимости от настроек терминала).

Обратите внимание, что при индексации необходимо учитывать дополнительный символ.

Также возможно нормализовать составленную строку вверсия с одним кодом ( canonical ) с использованием инструментов модуля unicodedata:

>>> unicodedata.normalize('NFC', u'costa\u0328m') ==  u"costąm"
True

, но это может вызвать проблемы, если, например, вы возвращаете измененную строку в систему, которая ожидаетобъединяющий символ, подлежащий сохранению.

0 голосов
/ 24 февраля 2019

Строка действительно выглядит так:

>>> list(dobry)
['c', 'o', 's', 't', '\xc4', '\x85', 'm']

Итак, dobry[5] == '\x85', потому что буква represented представлена ​​ двумя байтами .Чтобы решить эту проблему, просто используйте Python 3 вместо Python 2.

...