UTF-16 как последовательность кодовых единиц в Python

У меня есть строка 'abç', которая в UTF-8 равна b'ab\xc3\xa7'.

Я хочу это в UTF-16, но не так:

b'ab\xc3\xa7'.decode('utf-8').encode('utf-16-be')

что дает мне:

b'\x00a\x00b\x00\xe7'

Ответ, который мне нужен, - это кодовые единицы UTF-16, то есть список целых чисел:

[32, 33, 327]

Есть ли какой-нибудь простой способ сделать это?

И конечно, наоборот. Учитывая список целых чисел, которые являются кодовыми единицами UTF-16, как мне преобразовать его в UTF-8?

327 — это 'Ň', а не 'ç', что равно 231, как вы можете определить из выходных данных (xe7 — это 231 десятичное число). Кроме того, 'a' и 'b' — это 97 и 98, а не 32 и 33, что было бы пробелом и восклицательным знаком.

Grismar 30.08.2024 01:37

Кстати: 'abç'.encode('utf-16-be') намного проще и проще, чем b'ab\xc3\xa7'.decode('utf-8').encode('utf-16-be'). До сих пор не ясно, чего вы на самом деле хотите. Коды? 16-битные целые числа? В зависимости от того, почему вы этого хотите, это также может повлиять на лучший способ сделать это, поэтому было бы полезно, если бы вы предоставили эту информацию в своем вопросе, хотя бы в качестве контекста.

Ulrich Eckhardt 30.08.2024 16:56

Технически они не являются кодовыми единицами.

Andj 30.08.2024 22:28
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
3
66
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Простое решение, которое может сработать во многих случаях, будет выглядеть примерно так:

def sort_of_get_utf16_code_units(s):
    return list(map(ord, s))


print(sort_of_get_utf16_code_units('abç')

Выход:

[97, 98, 231]

Однако это не работает для персонажей за пределами Базовой многоязычной плоскости (BMP):

print(sort_of_get_utf16_code_units('😊'))

Выходные данные — это кодовая точка Unicode:

[128522]

Где вы могли ожидать кодовые единицы (как указано в вашем вопросе):

[55357, 56842]

Чтобы получить это:

def get_utf16_code_units(s):
    utf16_bytes = s.encode('utf-16-be')
    return [int.from_bytes(utf16_bytes[i:i+2]) for i in range(0, len(utf16_bytes), 2)]


print(get_utf16_code_units('😊'))

Выход:

[55357, 56842]

Обратное действие аналогично:

def utf16_code_units_to_string(code_units):
    utf16_bytes = b''.join([unit.to_bytes(2, byteorder='big') for unit in code_units])
    return utf16_bytes.decode('utf-16-be')


print(utf16_code_units_to_string([55357, 56842]))

Выход:

😊

По умолчанию порядок байтов равен 'big', но здесь не помешает уточнить.

Вы также можете использовать лямбда-функцию: get_utf16_code_units = lambda b: [int.from_bytes(b .encode('utf-16-be')[i:i+2]) for i in range(0, len(b .encode('utf-16-be')), 2)] и utf16_code_units_to_string = lambda c: (b''.join([unit.to_bytes(2, byteorder='big') for unit in c])).decode('utf-16-be').

DeepThought42 30.08.2024 03:35

Назначать лямбда-выражение имени — плохая практика, в этом нет никакой пользы, кроме сохранения строки в текстовом файле, и есть явные недостатки как в производительности, так и в читабельности.

Grismar 30.08.2024 05:04

@Grismar Как это влияет на производительность?

no comment 30.08.2024 05:38

Да, он компилируется в точно такой же байт-код.

DeepThought42 30.08.2024 06:58

Используйте array.array, чтобы быстро распаковать байтовую строку как беззнаковые шорты и получить кодовые единицы UTF-16:

import array

def utf16_code_units(s):
    return array.array('H', s.encode('utf-16le')).tolist()

print(utf16_code_units('abç💩'))

Выход:

[97, 98, 231, 55357, 56489]

Если вам нужна производительность, .tolist() не является обязательным, поскольку array.array имеет вид списка:

>>> array.array('H', 'abç💩'.encode('utf-16le'))
array('H', [97, 98, 231, 55357, 56489])

Другие вопросы по теме