Как перекодировать строку из utf 8 в windows 1251

Проблема кодировок часто возникает при написании парсеров, чтении данных из xml и CSV файлов. Ниже представлены способы эту проблему решить.

1

windows-1251 в UTF-8

$text = iconv('windows-1251//IGNORE', 'UTF-8//IGNORE', $text);
echo $text;

PHP

$text = mb_convert_encoding($text, 'UTF-8', 'windows-1251');
echo $text;

PHP

2

UTF-8 в windows-1251

$text = iconv('utf-8//IGNORE', 'windows-1251//IGNORE', $text);
echo $text;

PHP

$text = mb_convert_encoding($text, 'windows-1251', 'utf-8');
echo $text;

PHP

3

Когда ни что не помогает

$text = iconv('utf-8//IGNORE', 'cp1252//IGNORE', $text);
$text = iconv('cp1251//IGNORE', 'utf-8//IGNORE', $text);
echo $text;

PHP

Иногда доходит до бреда, но работает:

$text = iconv('utf-8//IGNORE', 'windows-1251//IGNORE', $text);
$text = iconv('windows-1251//IGNORE', 'utf-8//IGNORE', $text);
echo $text;

PHP

4

File_get_contents / CURL

Бывают случаи когда file_get_contents() или CURL возвращают иероглифы (Алмазные борÑ) – причина тут не в кодировке, а в отсутствии BOM-метки.

$text = file_get_contents('https://example.com');
$text = "\xEF\xBB\xBF" .  $text;
echo $text;

PHP

Ещё бывают случаи, когда file_get_contents() возвращает текст в виде:

�mw�Ƒ0�����&IkAI��f��j4/{�</�&�h�� ��({�񌝷o�����:/��<g���g��(�=�9�Paɭ

Это сжатый текст в GZIP, т.к. функция не отправляет правильные заголовки. Решение проблемы через CURL:

function getcontents($url){
	$ch = curl_init();
	curl_setopt($ch, CURLOPT_URL, $url);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
	curl_setopt($ch, CURLOPT_ENCODING, 'gzip');
	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
	$output = curl_exec($ch);
	curl_close($ch);
	return $output;
}

echo getcontents('https://example.com');

PHP

12.01.2017, обновлено 02.11.2021

Другие публикации

Отправка e-mail в кодировке UTF-8 с вложенными файлами и возможные проблемы.

JSON (JavaScript Object Notation) – текстовый формат обмена данными, основанный на JavaScript, который представляет собой набор пар {ключ: значение}. Значение может быть массивом, числом, строкой и…

Описание значений глобального массива $_SERVER с примерами.

Так как Instagram и Fasebook ограничили доступ к API, а фото с открытого аккаунта всё же нужно периодически получать и…

В статье представлены различные PHP-расширения для чтения файлов XLS, XLSX, описаны их плюсы и минусы, а также примеры…

Примеры как зарегистрировать бота в Телеграм, описание и взаимодействие с основными методами API.

REPA

Функция на языке Си для конвертации строк из кодировки UTF-8 в Windows-1251 (CP1251)

Файл с функцией: https://github.com/0x1801/REPA/blob/main/utf8_2_win1251.c

  • Поставляется в виде исходного кода.
  • Написана на языке С.
  • Может быть использована в программах на языке C++.
  • Может применяться в программах для микроконтроллеров
  • Не использует ни SIMD-инструкций, ни даже x64.
  • Использует очень мало памяти: 1 массив на 32 байта (компилятор кладет его в векторный регистр, если он есть) + несколько констант.
  • Поддерживает символы utf8 до 4х байт (стандарт RFC 3629)
  • Входной массив может совпадать с выходным: данные будут перезаписаны.

Применение:

Вам ничего не понадобится, кроме текста функции и 3х макросов перед ней. Ни инклюдов и библиотек, ни массивов, никакого другого кода. Просто скопируйте ее в свой проект.

ВНИМАНИЕ: Функция требует наличия 2х лишних выделенных байтов памяти за символом конца строки во входном массиве с символами utf8. В этих байтах может лежать любой мусор. Обычно, если в вашем проекте код написан оптимально, то вы не будете каждый раз выделять память под строку. Поэтому выделить 2 лишних байта — это не проблема. Но если в вашем проекте сложно это внедрить, то можете немного самостоятельно модифицировать код.

Если есть желание проверить работу функции, можно написать тест самостоятельно или воспользоваться заготовкой из main.c: https://github.com/0x1801/REPA/blob/main/main.c

Больше main.c ни для чего не нужен.

БОНУС: в файле https://github.com/0x1801/REPA/blob/main/koi8r_2_windows1251_AVX512.c можно найти функцию конвертации из любой 8-битной ASCII-совместимой кодировки в любую 8-битную ASCII-совместимую кодировку, написанную с использованием векторных инструкций AVX512. В коде для примера реализована конвертация из koi8r в windows 1251, но алгоритм пригоден для конвертации любоых сочетаний 8-битных кодировок, совместимых с ASCII. Признаюсь честно, что сам я ее тестировать поленился, т.к. msvc 2015 «из коробки» не знает функций, которые я использовал. Функция, как минимум, компилируется (в коментарии к ней ссылка на godbolt.org). Просто мне было интересно написать функцию, которая умеет конвертировать сразу 64 символа всего за 12 инструкций (само отображение занимает при этом вообще 2 инструкции). Если вам удастся протестировать функцию или найти в ней ошибки (или улучшения), напишите мне, пожалуйста.

Связаться с автором:

Илья

chronosphere@mail.ru.

Конвертирует строку из UTF-8 в Windows-1251

static string UTF8ToWin1251(string sourceStr)
{
Encoding utf8 = Encoding.UTF8;
Encoding win1251 = Encoding.GetEncoding(«Windows-1251»);
byte[] utf8Bytes = utf8.GetBytes(sourceStr);
byte[] win1251Bytes = Encoding.Convert(utf8, win1251, utf8Bytes);
return win1251.GetString(win1251Bytes);
}

Конвертирует строку из Windows-1251 в UTF-8

static private string Win1251ToUTF8(string source)
{
Encoding utf8 = Encoding.GetEncoding(«utf-8»);
Encoding win1251 = Encoding.GetEncoding(«windows-1251»);
byte[] utf8Bytes = win1251.GetBytes(source);
byte[] win1251Bytes = Encoding.Convert(win1251, utf8, utf8Bytes);
source = win1251.GetString(win1251Bytes);
return source;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
 
 
#define LINE_MAX 1024
 
 
int convert_utf8_to_windows1251(const char* utf8, char* windows1251, size_t n);
 
 
int main(int argc, char ** argv)
{
        //printf("start %s\n", argv[0]);
 
 
        if (argc <= 1) {
                printf("forgot file name for conversion");
                exit(EXIT_FAILURE);
        }
 
 
        FILE* file = fopen(argv[1], "r");
        if (!file) {
                perror("can't open file");
                exit(EXIT_FAILURE);
        }
 
 
        while(!feof(file)) {
                char buff[LINE_MAX] = {0};
                if (!fgets(buff, LINE_MAX, file)) {
                        perror("can't read line from file");
                        exit(EXIT_FAILURE);
                }
 
 
                char output[LINE_MAX] = {0};
                if (!convert_utf8_to_windows1251(buff, output, LINE_MAX)) {
                        printf("can't convert line: %s\n", buff);
                        exit(EXIT_FAILURE);
                }
                printf("%s", output);
        };
 
 
        return EXIT_SUCCESS;
}
 
 
typedef struct ConvLetter {
        char    win1251;
        int             unicode;
} Letter;
 
 
static Letter g_letters[] = {
        {0x82, 0x201A}, // SINGLE LOW-9 QUOTATION MARK
        {0x83, 0x0453}, // CYRILLIC SMALL LETTER GJE
        {0x84, 0x201E}, // DOUBLE LOW-9 QUOTATION MARK
        {0x85, 0x2026}, // HORIZONTAL ELLIPSIS
        {0x86, 0x2020}, // DAGGER
        {0x87, 0x2021}, // DOUBLE DAGGER
        {0x88, 0x20AC}, // EURO SIGN
        {0x89, 0x2030}, // PER MILLE SIGN
        {0x8A, 0x0409}, // CYRILLIC CAPITAL LETTER LJE
        {0x8B, 0x2039}, // SINGLE LEFT-POINTING ANGLE QUOTATION MARK
        {0x8C, 0x040A}, // CYRILLIC CAPITAL LETTER NJE
        {0x8D, 0x040C}, // CYRILLIC CAPITAL LETTER KJE
        {0x8E, 0x040B}, // CYRILLIC CAPITAL LETTER TSHE
        {0x8F, 0x040F}, // CYRILLIC CAPITAL LETTER DZHE
        {0x90, 0x0452}, // CYRILLIC SMALL LETTER DJE
        {0x91, 0x2018}, // LEFT SINGLE QUOTATION MARK
        {0x92, 0x2019}, // RIGHT SINGLE QUOTATION MARK
        {0x93, 0x201C}, // LEFT DOUBLE QUOTATION MARK
        {0x94, 0x201D}, // RIGHT DOUBLE QUOTATION MARK
        {0x95, 0x2022}, // BULLET
        {0x96, 0x2013}, // EN DASH
        {0x97, 0x2014}, // EM DASH
        {0x99, 0x2122}, // TRADE MARK SIGN
        {0x9A, 0x0459}, // CYRILLIC SMALL LETTER LJE
        {0x9B, 0x203A}, // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
        {0x9C, 0x045A}, // CYRILLIC SMALL LETTER NJE
        {0x9D, 0x045C}, // CYRILLIC SMALL LETTER KJE
        {0x9E, 0x045B}, // CYRILLIC SMALL LETTER TSHE
        {0x9F, 0x045F}, // CYRILLIC SMALL LETTER DZHE
        {0xA0, 0x00A0}, // NO-BREAK SPACE
        {0xA1, 0x040E}, // CYRILLIC CAPITAL LETTER SHORT U
        {0xA2, 0x045E}, // CYRILLIC SMALL LETTER SHORT U
        {0xA3, 0x0408}, // CYRILLIC CAPITAL LETTER JE
        {0xA4, 0x00A4}, // CURRENCY SIGN
        {0xA5, 0x0490}, // CYRILLIC CAPITAL LETTER GHE WITH UPTURN
        {0xA6, 0x00A6}, // BROKEN BAR
        {0xA7, 0x00A7}, // SECTION SIGN
        {0xA8, 0x0401}, // CYRILLIC CAPITAL LETTER IO
        {0xA9, 0x00A9}, // COPYRIGHT SIGN
        {0xAA, 0x0404}, // CYRILLIC CAPITAL LETTER UKRAINIAN IE
        {0xAB, 0x00AB}, // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
        {0xAC, 0x00AC}, // NOT SIGN
        {0xAD, 0x00AD}, // SOFT HYPHEN
        {0xAE, 0x00AE}, // REGISTERED SIGN
        {0xAF, 0x0407}, // CYRILLIC CAPITAL LETTER YI
        {0xB0, 0x00B0}, // DEGREE SIGN
        {0xB1, 0x00B1}, // PLUS-MINUS SIGN
        {0xB2, 0x0406}, // CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I
        {0xB3, 0x0456}, // CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
        {0xB4, 0x0491}, // CYRILLIC SMALL LETTER GHE WITH UPTURN
        {0xB5, 0x00B5}, // MICRO SIGN
        {0xB6, 0x00B6}, // PILCROW SIGN
        {0xB7, 0x00B7}, // MIDDLE DOT
        {0xB8, 0x0451}, // CYRILLIC SMALL LETTER IO
        {0xB9, 0x2116}, // NUMERO SIGN
        {0xBA, 0x0454}, // CYRILLIC SMALL LETTER UKRAINIAN IE
        {0xBB, 0x00BB}, // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
        {0xBC, 0x0458}, // CYRILLIC SMALL LETTER JE
        {0xBD, 0x0405}, // CYRILLIC CAPITAL LETTER DZE
        {0xBE, 0x0455}, // CYRILLIC SMALL LETTER DZE
        {0xBF, 0x0457} // CYRILLIC SMALL LETTER YI
};
 
 
 
 
 
 
int convert_utf8_to_windows1251(const char* utf8, char* windows1251, size_t n)
{
        int i = 0;
        int j = 0;
        for(; i < (int)n && utf8[i] != 0; ++i) {
                char prefix = utf8[i];
                char suffix = utf8[i+1];
                if ((prefix & 0x80) == 0) {
                        windows1251[j] = (char)prefix;
                        ++j;
                } else if ((~prefix) & 0x20) {
                        int first5bit = prefix & 0x1F;
                        first5bit <<= 6;
                        int sec6bit = suffix & 0x3F;
                        int unicode_char = first5bit + sec6bit;
 
 
                        if ( unicode_char >= 0x410 && unicode_char <= 0x44F ) {
                                windows1251[j] = (char)(unicode_char - 0x350);
                        } else if (unicode_char >= 0x80 && unicode_char <= 0xFF) {
                                windows1251[j] = (char)(unicode_char);
                        } else if (unicode_char >= 0x402 && unicode_char <= 0x403) {
                                windows1251[j] = (char)(unicode_char - 0x382);
                        } else {
                                int count = sizeof(g_letters) / sizeof(Letter);
                                for (int k = 0; k < count; ++k) {
                                        if (unicode_char == g_letters[k].unicode) {
                                                windows1251[j] = g_letters[k].win1251;
                                                goto NEXT_LETTER;
                                        }
                                }
                                // can't convert this char
                                return 0;
                        }
NEXT_LETTER:
                        ++i;
                        ++j;
                } else {
                        // can't convert this chars
                        return 0;
                }
        }
        windows1251[j] = 0;
        return 1;
}

Привет, друзья. Я уже 3 года работаю с вебом, но с таким не встречался еще. В чем суть:
Есть у меня кириллический текст с кодировкой UTF-8 и отображается он нормально.
Мне нужно изменить кодировку на windows-1251 так, чтобы кириллический текст так же нормально читабельно отображался. И вот что-то ну вообще не могу взять в толк, как это сделать?


  • Вопрос задан

  • 29548 просмотров

Пригласить эксперта

для большого количества файлов есть однострочник на powershell:

Get-ChildItem folderwithfiles -File | foreach {Get-Content $_.fullname -Encoding UTF8 | Out-File folderwithconvertedfiles\$_ -encoding default}

Одна загвоздка : encoding default — берет кодировку системы.
Проверить что это windows 1251 можно так(powershell) :
[System.Text.Encoding]::Default.Codepage

Вы имеете в виду, самостоятельно, а не в программном коде? Тогда с помощью Вашего текстового редактора, которым Вы пользуетесь. Например, если Вы предпочитаете Sublime Text, то просто воспользуйтесь пунктом меню File->Save with encoding > Cyrillic (Windows 1251)

Войдите, чтобы написать ответ


  • Показать ещё
    Загружается…

Минуточку внимания

Понравилась статья? Поделить с друзьями:
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
  • Windows 10 нормальная винда
  • Как проверить частоту процессора windows 10
  • Reliability monitor windows 11
  • Как включить службу поиска в windows 10
  • Windows game bar ошибка