Ответ 1
Вы запутали Unicode с UTF-8. Latin-1 - это подмножество Unicode, но это не подмножество UTF-8. Избегайте, как чума когда-либо думает об отдельных единицах кода. Просто используйте коды. Не думайте о UTF-8. Подумайте о Unicode. Здесь вас путают.
Исходный код для демонстрационной программы
Использование Unicode в Python очень просто. Его особенно с Python 3 и широкими сборками, единственный способ использовать Python, но вы все равно можете использовать устаревший Python 2 под узкой сборкой, если будете осторожны с тем, чтобы придерживаться UTF-8.
Для этого всегда правильно кодируйте исходный код и правильное кодирование вывода в UTF-8. Теперь перестаньте думать о UTF-ничего и используйте только буквы UTF-8, номера логических кодовых точек или символические имена символов во всей вашей программе Python.
Получает исходный код с номерами строк:
% cat -n /tmp/py
1 #!/usr/bin/env python3.2
2 # -*- coding: UTF-8 -*-
3
4 from __future__ import unicode_literals
5 from __future__ import print_function
6
7 import sys
8 import os
9 import re
10
11 if not (("PYTHONIOENCODING" in os.environ)
12 and
13 re.search("^utf-?8$", os.environ["PYTHONIOENCODING"], re.I)):
14 sys.stderr.write(sys.argv[0] + ": Please set your PYTHONIOENCODING envariable to utf8\n")
15 sys.exit(1)
16
17 print('1a: el ni\xF1o')
18 print('2a: el nin\u0303o')
19
20 print('1a: el niño')
21 print('2b: el niño')
22
23 print('1c: el ni\N{LATIN SMALL LETTER N WITH TILDE}o')
24 print('2c: el nin\N{COMBINING TILDE}o')
И вот функции печати с их символами без символов ASCII uniquote с использованием обозначения \x{⋯}
:
% grep -n ^print /tmp/py | uniquote -x
17:print('1a: el ni\xF1o')
18:print('2a: el nin\u0303o')
20:print('1b: el ni\x{F1}o')
21:print('2b: el nin\x{303}o')
23:print('1c: el ni\N{LATIN SMALL LETTER N WITH TILDE}o')
24:print('2c: el nin\N{COMBINING TILDE}o')
Примеры прогонов демонстрационной программы
Вот пример запуска этой программы, который показывает три разных способа выполнения (a, b и c): первый набор как литералы в исходном коде (который будет подчиняться преобразованиям NFC StackOverflows и, следовательно, не может быть доверенный!!!), а второй два набора с числовыми кодами Unicode и символическими именами символов Unicode соответственно, снова uniquote, чтобы вы могли видеть, что на самом деле есть:
% python /tmp/py
1a: el niño
2a: el niño
1b: el niño
2b: el niño
1c: el niño
2c: el niño
% python /tmp/py | uniquote -x
1a: el ni\x{F1}o
2a: el nin\x{303}o
1b: el ni\x{F1}o
2b: el nin\x{303}o
1c: el ni\x{F1}o
2c: el nin\x{303}o
% python /tmp/py | uniquote -v
1a: el ni\N{LATIN SMALL LETTER N WITH TILDE}o
2a: el nin\N{COMBINING TILDE}o
1b: el ni\N{LATIN SMALL LETTER N WITH TILDE}o
2b: el nin\N{COMBINING TILDE}o
1c: el ni\N{LATIN SMALL LETTER N WITH TILDE}o
2c: el nin\N{COMBINING TILDE}o
Мне очень не нравится смотреть на двоичный файл, но вот что это выглядит как двоичные байты:
% python /tmp/py | uniquote -b
1a: el ni\xC3\xB1o
2a: el nin\xCC\x83o
1b: el ni\xC3\xB1o
2b: el nin\xCC\x83o
1c: el ni\xC3\xB1o
2c: el nin\xCC\x83o
Мораль истории
Даже если вы используете источник UTF-8, вы должны думать и использовать только логические номера кодовых номеров Unicode (или символические именованные символы), а не отдельные 8-битные единицы кода, которые лежат в основе последовательного представления UTF-8 (или для это вопрос UTF-16). Чрезвычайно редко нужны кодовые единицы вместо кодовых точек, и это просто путает вас.
Вы также получите более надежное поведение, если используете широкую сборку Python3, чем вы получите альтернативы этим выборам, но это вопрос UTF-32, а не UTF-8. С UTF-32 и UTF-8 легко работать, если вы просто переходите с потоком.