Справочная система SDK КОМПАС-3D
Unicode — стандарт кодирования символов, позволяющий представить знаки практически всех письменных языков, т.е. это уникальный код для любого символа, независимо от платформы, независимо от программы, независимо от языка.
Стандарт состоит из двух основных разделов: универсальный набор символов (UCS, Universal Character Set) и семейство кодировок (UTF, Unicode Transformation Format).
Коды в стандарте Unicode разделены на несколько областей. Область с кодами от U+0000 до U+007F содержит символы набора ASCII с соответствующими кодами. Далее расположены области знаков различных письменностей, знаки пунктуации и технические символы. Часть кодов зарезервирована для использования в будущем. Под символы кириллицы выделены коды от U+0400 до U+052F (см. https://ru.wikipedia.org/wiki/Кириллица_в_Юникоде .
Имеется несколько форм представления: http://ru.wikipedia.org/wiki/UTF-8 , http://ru.wikipedia.org/wiki/UTF-16 (UTF-16BE, UTF-16LE) и UTF-32 (UTF-32BE, UTF-32LE)
В системах Windows 2000 и XP используется двухбайтовая форма UTF-16LE для внутреннего представления имен файлов и других системных строк. В UNIX-подобных операционных системах GNU/Linux, BSD и Mac OS X принята форма UTF-8 для файлов и UTF-32 или UTF-8 для обработки символов в оперативной памяти.
Начиная с Windows 2000, служебная программа «Таблица символов» отображает таблицу всех символов от U+0000 до U+FFFF, поддерживаемых конкретным шрифтом. Эта программа позволяет выбирать отдельные символы и копировать их в буфер обмена для последующей вставки. Более универсальный способ ввода символа, код которого известен, состоит в следующем: нажать клавишу ALT и, удерживая ее , набрать на дополнительной цифровой клавиатуре код требуемого символа в десятичной системе счисления. Например, нажатие ALT+0241 вставит букву «ñ».
Как любая изобретенная человеком система, Unicode не свободен от недостатков, например, некоторые системы письма все еще не представлены должным образом, а еще файлы с текстом в Unicode занимают больше места в памяти, так как один символ кодируется не одним байтом, как в различных национальных кодировках, а последовательностью байтов (исключение составляет UTF-8 для языков, алфавит которых укладывается в ASCII).
© ООО «АСКОН-Системы проектирования», 2023. Все права защищены. | Единая телефонная линия: 8-800-700-00-78
Юникод для чайников
Сам я не очень люблю заголовки вроде «Покемоны в собственном соку для чайников\кастрюль\сковородок», но это кажется именно тот случай — говорить будем о базовых вещах, работа с которыми довольно часто приводить к купе набитых шишек и уйме потерянного времени вокруг вопроса — «Почему же оно не работает?». Если вы до сих пор боитесь и\или не понимаете Юникода — прошу под кат.
Зачем?
Главный вопрос новичка, который встречается с впечатляющим количеством кодировок и на первый взгляд запутанными механизмами работы с ними (например, в Python 2.x). Краткий ответ — потому что так сложилось 🙂
Кодировкой, кто не знает, называют способ представления в памяти компьютера (читай — в нулях-единицах\числах) цифр, буков и всех остальных знаков. Например, пробел представляется как 0b100000 (в двоичной), 32 (в десятичной) или 0x20 (в шестнадцатеричной системе счисления).
Так вот, когда-то памяти было совсем немного и всем компьютерам было достаточно 7 бит для представления всех нужных символов (цифры, строчный\прописной латинский алфавит, куча знаков и так называемые управляемые символы — все возможные 127 номеров были кому-то отданы). Кодировка в это время была одна — ASCII. Шло время, все были счастливы, а кто не был счастлив (читай — кому не хватало знака «©» или родной буквы «щ») — использовали оставшиеся 128 знаков на свое усмотрение, то есть создавали новые кодировки. Так появились и ISO-8859-1, и наши (то есть кириличные) cp1251 и KOI8. Вместе с ними появилась и проблема интерпретации байтов типа 0b1******* (то есть символов\чисел от 128 и до 255) — например, 0b11011111 в кодировке cp1251 это наша родная «Я», в тоже время в кодировке ISO-8859-1 это греческая немецкая Eszett (подсказывает Moonrise) «ß». Ожидаемо, сетевая коммуникация и просто обмен файлами между разными компьютерами превратились в чёрт-знает-что, несмотря на то, что заголовки типа ‘Content-Encoding’ в HTTP протоколе, email-письмах и HTML-страницах немного спасали ситуацию.
В этот момент собрались светлые умы и предложили новый стандарт — Unicode. Это именно стандарт, а не кодировка — сам по себе Юникод не определяет, как символы будут сохранятся на жестком диске или передаваться по сети. Он лишь определяет связь между символом и некоторым числом, а формат, согласно с которым эти числа будут превращаться в байты, определяется Юникод-кодировками (например, UTF-8 или UTF-16). На данный момент в Юникод-стандарте есть немного более 100 тысяч символов, тогда как UTF-16 позволяет поддерживать более одного миллиона (UTF-8 — и того больше).
Ближе к делу!
Естественно, есть поддержка Юникода и в Пайтоне. Но, к сожалению, только в Python 3 все строки стали юникодом, и новичкам приходиться убиваться об ошибки типа:
>>> with open('1.txt') as fh: s = fh.read() >>> print s кощей >>> parser_result = u'баба-яга' # присвоение для наглядности, представим себе, что это результат работы какого-то парсера >>> parser_result + s
Traceback (most recent call last): File "", line 1, in parser_result + s UnicodeDecodeError: 'ascii' codec can't decode byte 0xea in position 0: ordinal not in range(128)
>>> str(parser_result)
Traceback (most recent call last): File "", line 1, in str(parser_result) UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-3: ordinal not in range(128)
Давайте разберемся, но по порядку.
Зачем кто-то использует Юникод?
Почему мой любимый html-парсер возвращает Юникод? Пусть возвращает обычную строку, а я там уже с ней разберусь! Верно? Не совсем. Хотя каждый из существующих в Юникоде символов и можно (наверное) представить в некоторой однобайтовой кодировке (ISO-8859-1, cp1251 и другие называют однобайтовыми, поскольку любой символ они кодируют ровно в один байт), но что делать если в строке должны быть символы с разных кодировок? Присваивать отдельную кодировку каждому символу? Нет, конечно, надо использовать Юникод.
Зачем нам новый тип «unicode»?
Вот мы и добрались до самого интересного. Что такое строка в Python 2.x? Это просто байты. Просто бинарные данные, которые могут быть чем-угодно. На самом деле, когда мы пишем что-нибудь вроде:
>>> x = 'abcd' >>> x 'abcd'
интерпретатор не создает переменную, которая содержит первые четыре буквы латинского алфавита, но только последовательность
('a', 'b', 'c', 'd')
с четырёх байт, и латинские буквы здесь используются исключительно для обозначения именно этого значения байта. То есть ‘a’ здесь просто синоним для написания ‘\x61’, и ни чуточку больше. Например:
>>> '\x61' 'a' >>> struct.unpack('>4b', x) # 'x' - это просто четыре signed/unsigned char-а (97, 98, 99, 100) >>> struct.unpack('>2h', x) # или два short-а (24930, 25444) >>> struct.unpack('>l', x) # или один long (1633837924,) >>> struct.unpack('>f', x) # или float (2.6100787562286154e+20,) >>> struct.unpack('>d', x * 2) # ну или половинка double-а (1.2926117739473244e+161,)
И ответ на вопрос — зачем нам «unicode» уже более очевиден — нужен тип, который будет представятся символами, а не байтами.
Хорошо, я понял чем есть строка. Тогда что такое Юникод в Пайтоне?
«type unicode» — это прежде всего абстракция, которая реализует идею Юникода (набор символов и связанных с ними чисел). Объект типа «unicode» — это уже не последовательность байт, но последовательность собственно символов без какого либо представления о том, как эти символы эффективно сохранить в памяти компьютера. Если хотите — это более высокой уровень абстракции, чем байтовый строки (именно так в Python 3 называют обычные строки, которые используются в Python 2.6).
Как пользоваться Юникодом?
>>> u'abc' u'abc'
>>> 'abc'.decode('ascii') u'abc'
>>> unicode('abc', 'ascii') u'abc'
'\x61' -> кодировка ascii -> строчная латинская "a" -> u'\u0061' (unicode-point для этой буквы) или '\xe0' -> кодировка c1251 -> строчная кириличная "a" -> u'\u0430'
Как из юникод-строки получить обычную? Закодировать её:
>>> u'abc'.encode('ascii') 'abc'
Алгоритм кодирования естественно обратный приведенному выше.
Запоминаем и не путаем — юникод == символы, строка == байты, и байты -> что-то значащее (символы) — это де-кодирование (decode), а символы -> байты — кодирование (encode).
Не кодируется 🙁
Разберем примеры с начала статьи. Как работает конкатенация строки и юникод-строки? Простая строка должна быть превращена в юникод-строку, и поскольку интерпретатор не знает кодировки, от использует кодировку по умолчанию — ascii. Если этой кодировке не удастся декодировать строку, получим некрасивую ошибку. В таком случае нам нужно самим привести строку к юникод-строке, используя правильную кодировку:
>>> print type(parser_result), parser_result баба-яга >>> s = 'кощей' >>> parser_result + s
Traceback (most recent call last): File "", line 1, in parser_result + s UnicodeDecodeError: 'ascii' codec can't decode byte 0xea in position 0: ordinal not in range(128)
>>> parser_result + s.decode('cp1251') u'\xe1\xe0\xe1\xe0-\xff\xe3\xe0\u043a\u043e\u0449\u0435\u0439' >>> print parser_result + s.decode('cp1251') баба-ягакощей >>> print '&'.join((parser_result, s.decode('cp1251'))) баба-яга&кощей # Так лучше :)
«UnicodeDecodeError» обычно есть свидетельством того, что нужно декодировать строку в юникод, используя правильную кодировку.
Теперь использование «str» и юникод-строк. Не используйте «str» и юникод строки 🙂 В «str» нет возможности указать кодировку, соответственно кодировка по умолчанию будет использоваться всегда и любые символы > 128 будут приводить к ошибке. Используйте метод «encode»:
>>> print type(s), s кощей >>> str(s)
Traceback (most recent call last): File "", line 1, in str(s) UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-4: ordinal not in range(128)
>>> s = s.encode('cp1251') >>> print type(s), s кощей
«UnicodeEncodeError» — знак того, что нам нужно указать правильную кодировку во время превращения юникод-строки в обычную (или использовать второй параметр ‘ignore’\’replace’\’xmlcharrefreplace’ в методе «encode»).
Хочу ещё!
Хорошо, используем бабу-ягу из примера выше ещё раз:
>>> parser_result = u'баба-яга' #1 >>> parser_result u'\xe1\xe0\xe1\xe0-\xff\xe3\xe0' #2 >>> print parser_result áàáà-ÿãà #3 >>> print parser_result.encode('latin1') #4 баба-яга >>> print parser_result.encode('latin1').decode('cp1251') #5 баба-яга >>> print unicode('баба-яга', 'cp1251') #6 баба-яга
- Что имеем на входе? Байты, которые IDLE передает интерпретатору. Что нужно на выходе? Юникод, то есть символы. Осталось байты превратить в символы — но ведь надо кодировку, правда? Какая кодировка будет использована? Смотрим дальше.
- Здесь важной момент:
>>> 'баба-яга' '\xe1\xe0\xe1\xe0-\xff\xe3\xe0' >>> u'\u00e1\u00e0\u00e1\u00e0-\u00ff\u00e3\u00e0' == u'\xe1\xe0\xe1\xe0-\xff\xe3\xe0' True
как видим, Пайтон не заморачивается с выбором кодировки — байты просто превращаются в юникод-поинты:
>>> ord('а') 224 >>> ord(u'а') 224
>>> parser_result.encode('latin1') '\xe1\xe0\xe1\xe0-\xff\xe3\xe0'
>>> parser_result.encode('latin1').decode('cp1251') u'\u0431\u0430\u0431\u0430-\u044f\u0433\u0430'
Есть ещё способ использования «u»» для представления, например, кириллицы, и при этом не указывать кодировку или нечитабельные юникод-поинты (то есть «u’\u1234’»). Способ не совсем удобный, но интересный — использовать unicode entity codes:
>>> s = u'\N\N\N\N\N' >>> print s кощей
Ну и вроде всё. Основные советы — не путать «encode»\«decode» и понимать различия между байтами и символами.
Python 3
Здесь без кода, ибо опыта нет. Свидетели утверждают, что там всё значительно проще и веселее. Кто возьмется на кошках продемонстрировать различия между здесь (Python 2.x) и там (Python 3.x) — респект и уважуха.
Полезно
Раз уж мы о кодировках, порекомендую ресурс, который время-от-времени помогает побороть кракозябры — http://2cyr.com/decode/?lang=ru.
Unicode HOWTO — официальный документ о том где, как и зачем Юникод в Python 2.x.
Спасибо за внимание. Буду благодарен за замечания в приват.
Unicode. Краткий обзор
Unicode представляет собой систему кодирования символов, которая используется компьютерами для хранения и обмена текстовыми данными. В Unicode имеется уникальный номер (или кодовый знак) для каждого символа основных мировых систем письменности. В эту систему также включены технические символы, знаки пунктуации и многие другие символы, используемые в письменности.
Помимо того что Unicode является таблицей кодов символов, он также включает в себя алгоритмы для сопоставления и кодирования двусторонней письменности, например, арабской, а также спецификации для нормализации текстовых форм.
В данном разделе приводится общее описание Unicode. Для получения более полной информации и списка поддерживаемых языков, символы которых могут быть закодированы с помощью Unicode, см.Веб-сайт Unicode Consortium.
Кодовые знаки
Символы представляют собой единицы информации, которые приблизительно соответствуют единице текста в письменной форме естественного языка. Unicode определяет то, каким образом символы будут интерпретироваться, а не отображаться.
Образ символа (глиф), который отображается, или визуальное представление символа, является знаком, который выводится на экране монитора или распечатанной странице. В некоторых системах записи один символ может соответствовать нескольким глифам, или несколько символов может соответствовать одному глифу. Например, «ll» в испанском языке является одним глифом, но двумя символами: «l» и «l».
В Unicode символы преобразуются в кодовые знаки. Кодовые знаки представляют собой числа, которые назначаются Unicode Consortium для каждого символа в каждой системе записи. Кодовые знаки представляются в виде записи «U+» и четырех чисел и/или букв. Ниже приводятся примеры кодовых знаков для четырех разных символов: строчная l, строчная u с умляутом, бета и строчной e с акутом.
Unicode содержит 1,114,112 кодовых значений; на настоящий момент времени, для них назначено более 96,000 символов.
Кодовое пространство Unicode для символов разделено на 17 уровней, каждый из которых содержит 65,536 кодовых знаков.
Первым уровнем (plane) – plane 0 – является Basic Multilingual Plane (BMP). Большая часть наиболее используемых символов кодируются с помощью BMP, и на сегодняшний день это уровень, на котором закодировано больше всего символов. BMP содержит кодовые знаки для почти всех символов современных языков и многих специальных символов. В BMP существует порядка 6,300 неиспользуемых кодовых знаков. Они будут использованы для добавления большего числа символов в будущем.
Следующим уровнем (plane) – plane 1 – является Supplementary Multilingual Plane (SMP). SMP используется для кодирования древних символов, а также музыкальных и математических символов.
Кодирование символов
Кодирование символов определяет каждый символ, его кодовый знак и то, как кодовый знак будет представлен в битах. Не зная, какое кодирование использовалось, вы не сможете интерпретировать строку символов корректно.
Существует очень большое количество схем кодирования, но конвертировать их данные между ними очень трудно, причем немногие из них могут учесть наличие символов более двух-трех разных языков. Например, если ваш ПК по умолчанию настроен на использование OEM-Latin II и вы просматриваете Веб-сайт, который использует IBM EBCDIC-Cyrillic, то все символы, которые будут представлены в Cyrillic, который не будет закодирован в схеме Latin II, не будут отображаться корректно. Такие символы будут замещены другими символами, например, знаками вопроса и квадратами.
Поскольку Unicode содержит кодовые знаки для большинства символов во всех современных языках, то использование кодировки символов Unicode позволит вашему компьютеру интерпретировать практически каждый известный символ.
Существует три основных схемы Юникод для кодирования символов: UTF-8, UTF-16 и UTF-32. UTF означает Unicode Transformation Format. Числа, которые идут за UTF, означают размер единиц (в байтах), используемых для кодирования.
- UTF-8 использует 8-битовую кодовую единицу переменной ширины. UTF-8 использует от 1 до 6 байт для кодирования символа; она может использовать меньше, столько же или больше байт, чем UTF-16 для кодирования одного и того же символа. В windows-1251, каждый код от 0 до 127 (U+0000 to U+0127) хранится в одном байте. Только кодовые знаки от 128 (U+0128) и выше хранятся с использованием от 2 до 6 байт.
- UTF-16 использует одну 16-битовую кодовую единицу фиксированной ширины. Он сравнительно компактен и все наиболее часто используемые символы могут быть закодированы с помощью одной 16-битовой кодовой единицы. Другие символы могут быть доступны при использовании пар 16-битовых кодовых единиц.
- UTF-32 требуется 4 байта для кодирования любого символа. В большинстве случаев документ, закодированный с помощью UTF-32, будет примерно в два раза больше, чем такой же документ, закодированный с помощью UTF-16. Каждый символ в нем кодируется с помощью одной 32-битовой единицы кодирования фиксированной ширины. Вы можете использовать UTF-32, если вы не ограничены в дисковом пространстве и хотите использовать одну кодовую единицу для каждого символа.
Все три формы кодирования могут кодировать одни и те же символы и могут быть переведены из одной в другую без потери данных.
Существуют и другие кодировки: например, UTF-7 и UTF-EBCDIC. Существует также кодировка GB18030, которая является китайским эквивалентом кодировки UTF-8 и поддерживает упрощенные и традиционные китайские символы. Для русского языка удобно пользоваться windows-1251.
Как устроен Юникод и зачем он нужен (в том числе и вам)
Это статья о том, что помогает нам выводить буквы на экран почти во всех компьютерах и смартфонах мира. Чисто для кругозора и понимания мира информационных технологий.
7-битная кодировка: первая таблица символов
Так-то компьютеры понятия не имеют про буквы и цифры. Они знают только единицы и нули.
Чтобы компьютер мог вывести на экран буквы, цифры и другие символы, ему их нужно две вещи:
- Знать, как эти символы выглядят, — какие пиксели зажигать, какие нет.
- Знать, какой символ какому коду соответствует, — чтобы выводить нужные символы.
Когда компьютеры только появлялись, для решения этой задачи придумали таблицу символов: в ней хранились рисунки символов и их код. Компьютер получал команды «выведи символ номер такой-то», он находит такой-то номер, запоминал рисунок символа, выводил его на экран и повторял это быстро-быстро, чтобы символов на экране было много.
В 1960-х годах, когда персональные компьютеры только появляться в США, в таблицах была только латиница и математические символы. Ещё были управляющие коды — они сообщали компьютеру, что делать с данными дальше. Всего таких символов набралось 127, а такая таблица называлась ASCII (Американский стандарт представления информации):
Каждый символ в этой таблице можно закодировать в семи битах (нолях и единицах), что в сумме давало 2⁷ = 128 символов:
000 0000 ← самый первый символ в таблице
111 1111 ← последний символ в таблице
Например, если считать с нуля, то заглавная буква A стоит на 65-м месте в таблице. Число 65 в десятичной системе — это 1000001 в двоичной, и это занимает как раз 7 бит.
Проблема этой таблицы в том, что с ней не получится закодировать русский текст — в таблице ASCII нет русских букв. И болгарский тоже не получится, как и китайский, арабский и прочие языки, где есть свои начертания букв.
8-битная кодировка: добавляются национальные символы
Чтобы компьютер мог выводить символы из других языков, семибитную таблицу кодировки расширили до восьмибитной. Это значит, что каждый символ в ней кодировался уже восемью битами, а в таблице могло поместиться 2⁸ = 256 символов.
В СССР такой восьмибитной таблицей стала КОИ-8 — в ней добавились символы русского алфавита и элементы псевдографики. В международном формате эта кодировка известна как KOI8-R. Для сохранения обратной совместимости первые 128 символов совпадают с кодировкой ASCII:
Хитрость этой кодировки в том, что если отбросить первый бит и превратить её в семибитную, то все почти все русские буквы превратятся в такие же латинские:
Ц →C и так далее
Это было сделано для сохранения максимальной совместимости текстов: если его открыть на компьютере, где нет КОИ-8, то текст всё равно получится прочитать, пусть и на латинице. Это прямо хардкорная обратная совместимость, но тогда это было необходимо: памяти было мало.
Проблема символьных языков
Восьмибитная кодировка решила проблему многих языков: дополнительные 128 ячеек позволили разместить много национальных букв алфавита. Но осталась проблема с другими языками, где дополнительных символов нужно гораздо больше, например:
- китайский,
- корейский,
- японский,
- тамильский,
- язык чероки,
- эфиопский.
В итоге каждая страна с такой письменностью делала свои таблицы кодировок. Это неудобно для всех, у кого нет таких таблиц: при открытии файла получался бессмысленный набор символов из той кодировки, что была под рукой.
Интернетные байки
В конце девяностых и начале двухтысячных в русскоязычном интернете была проблема с кодировками русских символов. В ходу было несколько восьмибитных кодировок: KOI-8R, Windows 1251 и ещё отдельная для MacOS. На главных страницах сайтов можно было прямо выбрать, в какой вам кодировке отобразить сайт. Не все браузеры поддерживали все эти кодировки, приходилось выкручиваться. Админы делали разные версии сайтов в разной кодировке — буквально клали на сервер разные файлы для разных кодировок.
По мере распространения компьютеров с Windows сайты стали делать в кодировке Win-1251, а потом все переползли на Юникод.
Юникод
Чтобы решить все проблемы с кодировками во всех странах, придумали Unicode — это сокращение от слов universal code (универсальный код). Идея в том, чтобы собрать все кодировки в одном месте — это позволит прочитать любой текст в любой стране, набранный на любом языке мира.
В Юникоде можно закодировать 1 112 064 символов — букв, знаков, иерогрифов, эмодзи, пиктограмм, глифов и других элементов письменности. Сейчас в Юникоде занято примерно 150 тысяч символов, но этого уже достаточно, чтобы охватить почти всю письменность мира. И, соответственно, ещё миллион символов ждёт, когда мы их придумаем.
Все современные операционные системы поддерживают Юникод, поэтому сейчас мы можем спокойно открыть любые файлы с китайскими иероглифами или арабской вязью.
Вот несколько примеров таблиц с разными символами Юникода. Числа под каждым символом — это порядковый номер символа в общей таблице.
Принципы Юникода
Гарантии стабильности — каждый символ всегда остаётся на своём месте. Даже если несколько лет спустя выяснится, что в таблицу забыли добавить важный для языка символ, он появится не рядом со своим языком, а на новой пустой позиции. Чтобы сгруппировать элементы языка в одном месте, используют национальные порядки сортировки, а не меняют записи в таблице. Это значит, что каждая новая версия Юникода полностью обратно совместима со всеми предыдущими.
Динамическая компоновка. Многие символы в Юникоде получаются соединением двух других, например A + ¨ = Ä. Есть исключения, но на общем фоне их немного.
Без оформления. Задача Юникода — передать смысл текста, а не его внешний вид. Это значит, что в кодировке нет правил оформления или выделения слов цветом.
Юникод кодирует простой текст без оформления. Считается, что простой текст должен хранить достаточно данных, чтобы читаемо отобразить его, и больше ничего.
Что не входит в Юникод
Кажется, что в Юникоде достаточно места, чтобы не фильтровать символы, а добавлять всё подряд. Но на деле есть свои ограничения:
- малоизвестная письменность, про которую пока мало данных;
- языки и письменности, где нет устоявшихся стандартов;
- нетекстовая письменность, например иератика и демотика — часть египетской клинописи (египетские иероглифы, кстати, в Юникоде есть).
Что дальше
В следующей части разберём, как символы Юникода кодируются и хранятся в виде наборов битов. Это не так просто, как кажется: нужно учесть технические ограничения при передаче данных и уметь переводить одни символы в другие.
Апскиллинг, как говорится
Апскиллинг — это, например, переход с уровня junior на уровень middle, а потом — senior. У «Яндекс Практикума» есть курсы ровно для этого: от алгоритмов и типов данных до модных фреймворков.
Получите ИТ-профессию
В «Яндекс Практикуме» можно стать разработчиком, тестировщиком, аналитиком и менеджером цифровых продуктов. Первая часть обучения всегда бесплатная, чтобы попробовать и найти то, что вам по душе. Дальше — программы трудоустройства.