Если вы с помощью PL\SQL делаете разбор почтовых сообщений (стандарта MIME) и получаете атрибуты (тема, тело сообщения, имена вложенных файлов и т.п.), Вы можете столкнуться с ситуацией, когда значение некоторых атрибутов дает подобный результат:
=?utf-8?B?cGxhbV/QutCw0Lot0YLQviDRgtCw0LpfMi5qcGc=?=
В моем случае я получал имя файла вложенного в письмо. Данное письмо я считывал из почтового ящика при помощи пакета MAIL_CLIENT.
Как оказалось когда имя файла во вложении было на латинице, то я его получал без проблем, но когда в имени файла содержались символы кириллицы, он кодировался в формат заголовка MIME с кодировкой UTF8.У Oracle для этих случаев есть пакет UTL_ENCODE, который позволяет кодировать и декодировать данные для почтовых сообщений.
В итоге написав следующую конструкцию, я решил проблему с кириллицей в имени файла:
file_name := case when filename like '=?utf-8?%' then utl_encode.mimeheader_decode(filename) else filename end; где, filename - это значение атрибута - имя вложенного файла в письме. А условие case нужно для того, чтобы выполнять декодирование строк формата заголовка MIME в UTF8, и не обрабатывать их, если имя содержит только латиницу.
В итоге я получил вместо:
=?utf-8?B?cGxhbV/QutCw0Lot0YLQviDRgtCw0LpfMi5qcGc=?=
нужное мне значение имени файла:
plam_как-то так_2.jpg
Для проверки:
select utl_encode.mimeheader_decode('=?utf-8?B?cGxhbV/QutCw0Lot0YLQviDRgtCw0LpfMi5qcGc=?=') VAL from dual; VAL ---------------------- plam_как-то так_2.jpg
Реализация DI в PHP
Jason-Webb 13.05.2025
Когда я начинал писать свой первый крупный PHP-проект, моя архитектура напоминала запутаный клубок спагетти. Классы создавали другие классы внутри себя, зависимости жостко прописывались в коде, а о. . .
Обработка изображений в реальном времени на C# с OpenCV
stackOverflow 13.05.2025
Объединение библиотеки компьютерного зрения OpenCV с современным языком программирования C# создаёт симбиоз, который открывает доступ к впечатляющему набору возможностей. Ключевое преимущество этого. . .
POCO, ACE, Loki и другие продвинутые C++ библиотеки
NullReferenced 13.05.2025
В C++ разработки существует такое обилие библиотек, что порой кажется, будто ты заблудился в дремучем лесу. И среди этого многообразия POCO (Portable Components) – как маяк для тех, кто ищет. . .
Паттерны проектирования GoF на C#
UnmanagedCoder 13.05.2025
Вы наверняка сталкивались с ситуациями, когда код разрастается до неприличных размеров, а его поддержка становится настоящим испытанием. Именно в такие моменты на помощь приходят паттерны Gang of. . .
Создаем CLI приложение на Python с Prompt Toolkit
py-thonny 13.05.2025
Современные командные интерфейсы давно перестали быть черно-белыми текстовыми программами, которые многие помнят по старым операционным системам. CLI сегодня – это мощные, интуитивные и даже. . .
Конвейеры ETL с Apache Airflow и Python
AI_Generated 13.05.2025
ETL-конвейеры – это набор процессов, отвечающих за извлечение данных из различных источников (Extract), их преобразование в нужный формат (Transform) и загрузку в целевое хранилище (Load). . . .
Выполнение асинхронных задач в Python с asyncio
py-thonny 12.05.2025
Современный мир программирования похож на оживлённый мегаполис – тысячи процессов одновременно требуют внимания, ресурсов и времени. В этих джунглях операций возникают ситуации, когда программа. . .
Работа с gRPC сервисами на C#
UnmanagedCoder 12.05.2025
gRPC (Google Remote Procedure Call) — открытый высокопроизводительный RPC-фреймворк, изначально разработанный компанией Google. Он отличается от традиционых REST-сервисов как минимум тем, что. . .
CQRS (Command Query Responsibility Segregation) на Java
Javaican 12.05.2025
CQRS — Command Query Responsibility Segregation, или разделение ответственности команд и запросов. Суть этого архитектурного паттерна проста: операции чтения данных (запросы) отделяются от операций. . .
Шаблоны и приёмы реализации DDD на C#
stackOverflow 12.05.2025
Когда я впервые погрузился в мир Domain-Driven Design, мне показалось, что это очередная модная методология, которая скоро канет в лету. Однако годы практики убедили меня в обратном. DDD — не просто. . .
Отображение текста, сохранённого в разных кодировках в бд с однобайтной кодировкой, через db link из UTF бд
Непрямой способ для редких случаев когда нужно одновременно получить / отобразить данные, сохранённые в разных однобайтовых кодировках
Вставка в бд с однобайтной кодировкой:
$ export LANG=russian $ export NLS_LANG=AMERICAN_CIS.CL8MSWIN1251 $ sqlplus scott/tiger SQL> select * from nls_database_parameters; PARAMETER VALUE ------------------------------ ---------------------------------------- NLS_CHARACTERSET CL8MSWIN1251 -- однобайтовая бд NLS_NCHAR_CHARACTERSET AL16UTF16 NLS_RDBMS_VERSION 11.2.0.3.0 SQL> create table nls_test(lang char(2), text varchar2(100)); Table created. SQL> insert into nls_test values('RU', 'Текст на русском языке'); 1 row created. SQL> insert into nls_test values('IW', 'םוןםי OIJOI םןחארגארארג'); 1 row created. SQL> commit; Commit complete. SQL> select * from nls_test; -- в кириллической кодировке на клиенте 1251 LAN TEXT --- ---------------------------------------------------------------------------------------------------- RU Текст на русском языке -- 1251 отображается правильно IW непнй OIJOI нпзашвашашв -- 1255 отображается кириллицей SQL> select * from nls_test; -- в иностранной кодировке 1255 LAN TEXT --- ---------------------------------------------------------------------------------------------------- RU ׂוךסע םא נףססךמל �ח�ךו -- всё отображается некириллическими символами IW םוןםי OIJOI םןחארגארארג
Преобразование символов в UTF8 коды в бд с однобайтовой кодировкой, как я понимаю, затруднительна:
SQL> select convert(text, 'CL8MSWIN1251', 'AL32UTF8') FROM scott.nls_test; select convert(text, 'CL8MSWIN1251', 'AL32UTF8') FROM scott.nls_test * ERROR at line 1: ORA-12703: this character set conversion is not supported
На соседней бд с UTF кодировкой, естественно, при использовании UTF шрифтов на клиенте (putty Translation -> UTF):
$ set | grep 'LANG\=' LANG=en_US.UTF-8 NLS_LANG=AMERICAN_CIS.UTF8 SQL> select value from nls_database_parameters where parameter = 'NLS_CHARACTERSET'; VALUE ----- UTF8 SQL> create database link scott_db1251 connect to scott IDENTIFIED BY tiger using 'db1251'; Database link created. SQL> select decode( lang, 'IW ', UTL_I18N.raw_to_char(UTL_I18N.STRING_TO_RAW(text, 'CL8MSWIN1251'), 'IW8MSWIN1255') 3 , 'RU ', UTL_I18N.raw_to_char(UTL_I18N.STRING_TO_RAW(text, 'CL8MSWIN1251'), 'CL8MSWIN1251') 4 , 'Unknown language') as "Text" 5 FROM nls_test@scott_db1251; Text ------------------------------------------------------------ Текст на русском языке םוןםי OIJOI םןחארגארארג
Метод, мягко говоря, непрямой, но работает на встроенных технологиях Oracle — промежуточная UTF бд играет роль «перекодирующего клиента»
Вопрос: есть ли более простой способ?
Комментарии к записи Отображение текста, сохранённого в разных кодировках в бд с однобайтной кодировкой, через db link из UTF бд отключены
Мне каждый раз задают один и тот же вопрос, спрашивают об одном и том же: «Как перекодировать кракозябры из базы данных, хранящей строки в кодировке latin1 в нормальную кириллицу (windows-1251) или utf-8».
Ниже я постараюсь наиболее полно ответить на данный вопрос, а также приведу кусок кода на PHP, который однозначно решает проблему.
Во-первых, я никому не рекомендую продолжать работать в кодировке windows-1251. Эта однобайтовая кодировка уже не удовлетворяет требованиям современности. Поскорее переводите все проекты на utf-8. Чем быстрее это будет сделано, тем быстрее пропадут у вас проблемы с кракозябрами.
Теперь о latin1. Эта кодировка (также известна как windows-1252) повсеместно использовалась ранее в MySQL вплоть до версии 4. Символьная таблица кириллических букв находится в ней на месте арабских символов. Но поскольку она тоже однобайтовая, то при чтении данных в этой кодировке из этой таблицы и выводе их как windows-1251 не возникает никаких проблем, ведь коды в итоге те же самые (0xA0-0xFF). Но всё это будет работать только до тех пор, пока вы не установите MySQL 5+, работающий по дефолту в utf-8.
Что же делает MySQL 5+, передавая Вам такие данные? Перед передачей на сторону клиента он честно перекодирует все данные в utf-8, помещая арабские символы (а в latin1 ваша кириллица на самом деле является арабскими символами) в тот диапазон кодов utf-8, где они и должны быть. В результате если вы даже попытаетесь перекодировать полученную utf-8-строку обратно в кириллицу функцией iconv(‘utf-8’, ‘windows-1251’, $str), то у вас ничего не получится. iconv выдаст ошибку, либо вернёт пустую строку.
Первое, что делает программист — он пытается изменить кодировку таблицы latin1 на windows-1251 в phpMyAdmin. Но MySQL этого сделать не может (о чём он и пишет), ведь в кодировке windows-1251 нет соответствующих арабских символов. Второе, что приходит в голову — сконвертировать эту таблицу в utf-8. И это получается. Только вот тексты по-прежнему отображаются кракозябрами.
Как же быть? Как решить эту проблему ?
Решение тут довольно простое, но чтобы к нему прийти самостоятельно, надо чётко понимать — что такое кодировки и как они работают. В понимании поможет моя hand-made диаграмма.
А вот и алгоритм, которым я пользуюсь, чтобы привести кодировки в порядок.
- Перевожу все таблицы БД в кодировку utf-8. При этом якобы кириллические символы, хранящиеся в кодировке latin1, а поэтому на самом деле являющиеся арабскими, переводятся в utf-8 и занимают свои законные места в диапазоне кодов utf-8, предназначенном для арабских символов.
- Пишу микроутилиту на PHP, которая делает следующее с каждой символьной строкой:
- а) Переводит строку в кодировку windows-1252. Тут проблем быть не должно. Тем самым арабские буквы занимают диапазон кодов A0-FF.
- б) Переводит полученную однобайтовую строку в utf-8, но уже не как windows-1252, а как windows-1251, т.е. выдавая символы из диапазона A0-FF за кириллические. В итоге символы попадают в utf-8 в тот диапазон кодов, который предназначен для кириллических символов.
- Всё, теперь наша строка официально является кириллической строкой в utf-8. Её можно записать обратно в ту же ячейку БД, либо сразу выдать в выходной поток. Однако я всё же рекомендую выполнить однократное полное преобразование БД, и забыть о latin1 как о страшном сне.
Ниже привожу сэмпл кода на PHP, который переводит ФИО пользователей в нормальную кириллическую кодировку.
$q = 'select id, fio from `users`';
$res = mysql_query($q);
while (($row = mysql_fetch_assoc($res)) !== false) {
// Преобразуем fio из utf-8/latin1 в windows-1252
$s = iconv('utf-8', 'windows-1252', $row['fio']);
// Преобразуем строку из однобайтной кодировки обратно в utf-8, выдав её за windows-1251
$s = iconv('windows-1251', 'utf-8', $s);
// Сохраняем назад в БД
$q = 'update `users` set fio = "'.addslashes($s).'" where id = '.$row['id'];
mysql_query($q);
}
Если эта публикация вас вдохновила и вы хотите поддержать автора — не стесняйтесь нажать на кнопку
Skip to content
The Oracle CONVERT()
function converts a string from one character set to another.
Note that the CONVERT()
function is often used to correct data stored in the database with a wrong character set.
Syntax #
The following shows the syntax of the Oracle CONVERT()
function:
CONVERT(string_expression,to_data_set[,from_data_set]);
Code language: SQL (Structured Query Language) (sql)
Arguments #
The Oracle CONVERT()
function accepts three arguments:
1) string_expression
is the string whose character set should be converted.
2) to_data_set
is the name of the character set to which the string_expression
is converted to:
3) from_data_set
is the name of the character set that is used to store the string_expression
in the database. This argument is optional and its default value is the database character set.
Return value #
The CONVERT()
function returns a string in the converted character set.
Examples #
The following example converts a string from ANSI to UTF8:
SELECT
CONVERT( 'ABC', 'utf8', 'us7ascii' )
FROM
dual;
Code language: SQL (Structured Query Language) (sql)
Here is the result:
'ABC'
Code language: SQL (Structured Query Language) (sql)
The following statement illustrates how to convert the character set of a string from Latin-1 to ASCII.
SELECT
CONVERT( 'Ä Ê Í', 'US7ASCII', 'WE8ISO8859P1' )
FROM
DUAL;
Code language: SQL (Structured Query Language) (sql)
The result is:
'A E I'
Code language: SQL (Structured Query Language) (sql)
Note that the result is the same as converting the string from the WE8ISO8859P1 character set to the US7ASCII character set.
The following table shows the common character sets:
Character Set | Description |
---|---|
AL32UTF8 | Unicode 5.0 Universal character set UTF-8 encoding form |
EE8MSWIN1250 | Microsoft Windows East European Code Page 1250 |
JA16SJISTILDE | Japanese Shift-JIS Character Set, compatible with MS Code Page 932 |
US7ASCII | US 7-bit ASCII character set |
UTF8 | Unicode 3.0 Universal character set CESU-8 encoding form |
WE8EBCDIC1047 | IBM West European EBCDIC Code Page 1047 |
WE8ISO8859P1 | ISO 8859-1 West European 8-bit character set |
WE8MSWIN1252 | Microsoft Windows West European Code Page 1252 |
ZHT16MSWIN950 | Microsoft Windows Traditional Chinese Code Page 950 |
To get all the valid character sets, you query them from the V$NLS_VALID_VALUES
view as follows:
SELECT
value
FROM
V$NLS_VALID_VALUES
WHERE
parameter = 'CHARACTERSET' AND ISDEPRECATED = 'FALSE'
ORDER BY
value;
Code language: SQL (Structured Query Language) (sql)
Summary #
- Use the Oracle
CONVERT()
function to convert a string from a character set to another.
Was this tutorial helpful?