Тема статьи — конвертация mp3-тегов, созданных в кодировке windows-1251, в кодировку utf-8, под управлением операционной системы Linux.
В чем проблема
Причина возникновения такого вопроса заключается в том, что я уже достаточно давно стал поклонником аудио-книг. И передачи “Модель для сборки” — в частности. И хотя сама передача уже давно закрыта, ее архивы в Интернете доступны для скачивания.
Дома у меня имеются только две операционные системы — Mac OS X 10.10 и Linux Mint 17 Cinnamon. И вот тут возникает небольшая проблема, связанная с тем, что Audacious под Linux и iTunes под Mac не отображают правильно мета-информацию проигрываемых mp3-файлов аудио-книг, если эти файлы созданы под Windows.
Другими словами, аудио-проигрыватель “читает” аудио-книгу, но вот понять визуально — какую, нельзя. Не видно названия книги, ее автора, имени чтеца. Происходит это потому, что оба вышеназванных проигрывателя не могут правильно отображать мета-данные mp3-файлов, если эти мета-данные созданы в кодировке windows-1251.
Как решить проблему
Решением вопроса является перекодировка мета-данных mp3-файлов, перевод символов из кодировки windows-1251 в кодировку utf-8, с которой умеют работать Audacious и iTunes.
Решение оказалось на удивление простое и “под рукой”. Популярный редактор mp3-тегов под Linux с названием EasyTAG в два счета справляется с задачей. Главное — нужно правильно настроить чтение mp3-тегов этой программой.
-
Устанавливаем программу EasyTAG
-
Переходим в настройки программы EasyTAG — “Edit — Preferences”
-
К окне настроек программы EasyTAG переходим на вкладку “ID3 Tag Settings”
-
Устанавливаем параметры программы EasyTAG так, как это показано на скриншоте:
Если описать двумя словами, то необходимо для “ID3v1 tags” выбрать кодировку Windows-1251, для “ID3v1 tags” выбрать кодировку utf-8. Для поля “Character Set for reading ID3 tags” также выбрать кодировку windows-1251.
Конвертация в программе EasyTAG
Когда программа EasyTAG настроена, то процесс конвертации mp3-тегов из кодировки windows-1251 в кодировку utf-8 выполнить проще простого.
-
Открываем в программе EasyTAG папку с коллекцией mp3-файлов, которые необходимо обработать (переконвертировать).
-
Выделяем в окне программы EasyTAG все эти файлы.
-
Сохраняем их.
Да, именно так — “открыл-сохранил”, ничего больше. И теперь Audacious вместе с iTunes прекрасно читают обработанные файлы музыки (и аудио-книг).
На этом все.
Актуальность XML в 2022 году была бы под вопросом, но все еще остается много legacy систем, которые могут предоставлять данные в этом формате, поэтому нам приходится с ним работать. XML популярен в travel индустрии. Например, GDS (международные системы бронирования, более подробно можно почитать о них в википедии) или информационная система Darwin ассоциации железнодорожных транспортных компаний Великобритании активно используют его. Поэтому, я надеюсь, что эта статья будет кому-то полезна. В ней рассмотрена пара подходов к парсингу xml в Golang: обычный и потоковый, пользовательский парсинг поля и работа с различными кодировками. Мы будем использовать пакет encoding/xml из стандартной библиотеки. Если вы уже работали c encoding/json, то будет много похожего, но некоторые различия все же есть.
Генерация Go структур по XML
Прежде всего нам понадобится описать go структуры, соответствующие xml файлам. Можно сделать это вручную c помощью структурных тегов (детальную информацию о том, как описывать теги для XML можно посмотреть в документации по методу Marshal). Но для скорости и простоты мы воспользуемся одним из многочисленных генераторов go структуры по xml, например https://github.com/miku/zek/ (обратите внимание, что есть онлайн версия этого генератора: https://www.onlinetool.io/xmltogo/). Если вы впервые сталкиваетесь с таким подходом, то рекомендую сначала ознакомиться, например, со статьей «Использование тегов структур в Go»
Парсинг XML в Go структуру
Начнем с простого xml файла и обычного Unmarshal в golang структуру. Пример файла я взял с сайта w3schools. Напомню, что сначала нам понадобится описать go struct, соответствующую структуре xml. Чтобы сделать это мы будем использовать тэги структур (аналогично json, если ранее не работали с json в golang, то можете почитать об этом здесь и здесь, на русском здесь и здесь).
Давайте посмотрим на пример XML файла:
<?xml version="1.0" encoding="UTF-8"?>
<breakfast_menu>
<food>
<name>Belgian Waffles</name>
<price>$5.95</price>
<description>Two of our famous Belgian Waffles with plenty of real maple syrup</description>
<calories>650</calories>
</food>
<food>
<name>Strawberry Belgian Waffles</name>
<price>$7.95</price>
<description>Light Belgian waffles covered with strawberries and whipped cream</description>
<calories>900</calories>
</food>
<food>
<name>Berry-Berry Belgian Waffles</name>
<price>$8.95</price>
<description>Light Belgian waffles covered with an assortment of fresh berries and whipped cream</description>
<calories>900</calories>
</food>
<food>
<name>French Toast</name>
<price>$4.50</price>
<description>Thick slices made from our homemade sourdough bread</description>
<calories>600</calories>
</food>
<food>
<name>Homestyle Breakfast</name>
<price>$6.95</price>
<description>Two eggs, bacon or sausage, toast, and our ever-popular hash browns</description>
<calories>950</calories>
</food>
</breakfast_menu>
И вот go структура, которая его описывает:
type BreakfastMenu struct {
XMLName xml.Name `xml:"breakfast_menu"`
Food []struct {
Name string `xml:"name"`
Price string `xml:"price"`
Description string `xml:"description"`
Calories string `xml:"calories"`
} `xml:"food"`
}
Дальше все достаточно тривиально. Код для Unmarshal (парсинг из xml в golang структуру) будет выглядеть следующим образом:
menu := new(BreakfastMenu)
err := xml.Unmarshal([]byte(data), menu)
if err != nil {
fmt.Printf("error: %v", err)
return
}
Соответственно Marshal (операция, обратная Unmarshal, из go структуры в xml):
xmlText, err := xml.MarshalIndent(menu, " ", " ")
if err != nil {
fmt.Printf("error: %v\n", err)
return
}
Полный текст программы вы можете посмотреть под катом и попробовать запустить по ссылке (обратите внимание, что мы используем MarshalIndent вместо Marshal – это функция позволяет вывести xml в более читаемом виде: добавить отступы и переносы строк.
Пример Golang XML Marshal/Unmarshal
package main
import (
"encoding/xml"
"fmt"
)
type BreakfastMenu struct {
XMLName xml.Name `xml:"breakfast_menu"`
//Text string `xml:",chardata"`
Food []struct {
//Text string `xml:",chardata"`
Name string `xml:"name"`
Price string `xml:"price"`
Description string `xml:"description"`
Calories string `xml:"calories"`
} `xml:"food"`
}
func main() {
menu := new(BreakfastMenu)
err := xml.Unmarshal([]byte(data), menu)
if err != nil {
fmt.Printf("error: %v", err)
return
}
fmt.Printf("--- Unmarshal ---\n\n")
for _, foodNode := range menu.Food {
fmt.Printf("Name: %s\n", foodNode.Name)
fmt.Printf("Price: %s\n", foodNode.Price)
fmt.Printf("Description: %s\n", foodNode.Description)
fmt.Printf("Calories: %s\n", foodNode.Calories)
fmt.Printf("---\n")
}
xmlText, err := xml.MarshalIndent(menu, " ", " ")
if err != nil {
fmt.Printf("error: %v\n", err)
return
}
fmt.Printf("\n--- Marshal ---\n\n")
fmt.Printf("xml: %s\n", string(xmlText))
}
var data = `
<?xml version="1.0" encoding="UTF-8"?>
<breakfast_menu>
<food>
<name>Belgian Waffles</name>
<price>$5.95</price>
<description>Two of our famous Belgian Waffles with plenty of real maple syrup</description>
<calories>650</calories>
</food>
<food>
<name>Strawberry Belgian Waffles</name>
<price>$7.95</price>
<description>Light Belgian waffles covered with strawberries and whipped cream</description>
<calories>900</calories>
</food>
<food>
<name>Berry-Berry Belgian Waffles</name>
<price>$8.95</price>
<description>Light Belgian waffles covered with an assortment of fresh berries and whipped cream</description>
<calories>900</calories>
</food>
<food>
<name>French Toast</name>
<price>$4.50</price>
<description>Thick slices made from our homemade sourdough bread</description>
<calories>600</calories>
</food>
<food>
<name>Homestyle Breakfast</name>
<price>$6.95</price>
<description>Two eggs, bacon or sausage, toast, and our ever-popular hash browns</description>
<calories>950</calories>
</food>
</breakfast_menu>
`
Таким образом, здесь все просто, но есть пара проблем: в том случае, если xml файл большого размера, то нам понадобится большое количество оперативной памяти, и в том случае, если мы получаем файл по сети нам понадобится дождаться получения полного содержимого, прежде чем начать парсинг. Давайте рассмотрим второй подход, который нам позволит решить эти проблемы.
Потоковый парсинг XML
Для потокового парсинга XML мы можем использовать тип Decoder, который позволяет парсить xml файл потоково и ожидает, что поток будет в кодировке UTF-8 (дословная цитата из документации: “A Decoder represents an XML parser reading a particular input stream. The parser assumes that its input is encoded in UTF-8.”)
С полным текстом программы можно под катом и запустить по ссылке.
Пример потокового парсинга XML в Golang
package main
import (
"bytes"
"encoding/xml"
"fmt"
)
const foodElementName = "food"
type BreakfastMenu struct {
Food []Food `xml:"food"`
}
type Food struct {
Name string `xml:"name"`
Price string `xml:"price"`
Description string `xml:"description"`
Calories string `xml:"calories"`
}
func main() {
var (
menu BreakfastMenu
food Food
)
xmlData := bytes.NewBufferString(data)
d := xml.NewDecoder(xmlData)
for t, _ := d.Token(); t != nil; t, _ = d.Token() {
switch se := t.(type) {
case xml.StartElement:
if se.Name.Local == foodElementName {
d.DecodeElement(&food, &se)
menu.Food = append(menu.Food, food)
}
}
}
fmt.Printf("--- Unmarshal ---\n\n")
for _, foodNode := range menu.Food {
fmt.Printf("Name: %s\n", foodNode.Name)
fmt.Printf("Price: %s\n", foodNode.Price)
fmt.Printf("Description: %s\n", foodNode.Description)
fmt.Printf("Calories: %s\n", foodNode.Calories)
fmt.Printf("---\n")
}
}
var (
data = `
<?xml version="1.0" encoding="UTF-8"?>
<breakfast_menu>
<food>
<name>Belgian Waffles</name>
<price>$5.95</price>
<description>Two of our famous Belgian Waffles with plenty of real maple syrup</description>
<calories>650</calories>
</food>
<food>
<name>Strawberry Belgian Waffles</name>
<price>$7.95</price>
<description>Light Belgian waffles covered with strawberries and whipped cream</description>
<calories>900</calories>
</food>
<food>
<name>Berry-Berry Belgian Waffles</name>
<price>$8.95</price>
<description>Light Belgian waffles covered with an assortment of fresh berries and whipped cream</description>
<calories>900</calories>
</food>
<food>
<name>French Toast</name>
<price>$4.50</price>
<description>Thick slices made from our homemade sourdough bread</description>
<calories>600</calories>
</food>
<food>
<name>Homestyle Breakfast</name>
<price>$6.95</price>
<description>Two eggs, bacon or sausage, toast, and our ever-popular hash browns</description>
<calories>950</calories>
</food>
</breakfast_menu>
`
)
Давайте посмотрим на основные изменения в коде и разберем их подробнее:
d := xml.NewDecoder(xmlData)
for t, _ := d.Token(); t != nil; t, _ = d.Token() {
switch se := t.(type) {
case xml.StartElement:
if se.Name.Local == foodElementName {
d.DecodeElement(&food, &se)
menu.Food = append(menu.Food, food)
}
}
}
Сначала инстанцируется xml.Decoder с помощью функции xml.NewDecoder. Далее происходит итерация по токенам xml с помощью метода Token. Он возвращает тип Token или nil, если достигнут конец файла. Строго говоря, метод возвращает два значения: Token и ошибку, если она произошла. В случае достижения конца файла возвращается nil для Token и io.EOF в качестве ошибки.
Тип xml.Token представляет собой интерфейс и объявлен как ‘type Token any’ (в свою очередь any объявлен как пустой интерфейс: ‘type any = interface{}’). До введения дженериков в Golang xml.Token был объявлен как пустой интерфейс: ‘type Token interface{}’. Таким образом, может содержать любой тип данных и, согласно документации, может быть одним из следующих типов: StartElement, EndElement, CharData, Comment, ProcInst или Directive. Нас будет интересовать только начало элемента, т.е. тип StartElement. Как только он нам встречается мы проверяем, что он является нодой “food”. Если это так, то декодируем в Go структуру с помощью метода Decode.
Пользовательский парсинг (custom unmarshal)
Иногда требуется описать свой декодер для определенного поля. Часто такое бывает в случае парсинга даты, времени, либо enum-ов. Сделать это можно с помощью пользовательского типа данных, который должен реализовать интерфейс Unmarshaler пакета encoding/xml. Интерфейс содержит только один метод: UnmarshalXML, давайте посмотрим на пример его реализации:
type userDate time.Time
const userDateFormat = "2006-01-02"
func (ud *userDate) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
dateString := ""
err := d.DecodeElement(&dateString, &start)
if err != nil {
return err
}
dat, err := time.Parse(userDateFormat, dateString)
if err != nil {
return err
}
*ud = userDate(dat)
return nil
}
Коротко говоря, метод принимает на вход инстанс текущего xml.Decoder и xml элемент (мы уже использовали тип данных xml.StartElement в потоковом парсинге), которые используются для декодирования элемента в строку. После чего мы парсим строку в тип time.Time (используем свой шаблон формата даты: userDateFormat) и присваиваем значения ресиверу ud, предварительно преобразовав тип к userDate. Полный текст программы вы можете посмотреть под катом и попробовать запустить по ссылке.
Custom unmarshal XML Golang
package main
import (
"encoding/xml"
"fmt"
"time"
)
type userDate time.Time
const userDateFormat = "2006-01-02"
type FilmsDB struct {
XMLName xml.Name `xml:"films"`
Film []Film `xml:"film"`
}
type Film struct {
Title string `xml:"title"`
ReleaseDate userDate `xml:"releaseDate"`
}
func (ud *userDate) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
dateString := ""
err := d.DecodeElement(&dateString, &start)
if err != nil {
return err
}
dat, err := time.Parse(userDateFormat, dateString)
if err != nil {
return err
}
*ud = userDate(dat)
return nil
}
func (ud userDate) String() string {
return time.Time(ud).Format(time.RFC822)
}
func main() {
filmsDB := new(FilmsDB)
err := xml.Unmarshal([]byte(data), filmsDB)
if err != nil {
fmt.Printf("error: %v", err)
return
}
fmt.Printf("--- Unmarshal ---\n\n")
for _, film := range filmsDB.Film {
fmt.Printf("Title: %s\n", film.Title)
fmt.Printf("Release Date: %s\n", film.ReleaseDate)
fmt.Printf("---\n")
}
}
var (
data = `
<?xml version="1.0" encoding="UTF-8"?>
<films>
<film>
<title>Johnny Mnemonic</title>
<releaseDate>1995-05-26</releaseDate>
</film>
</films>
`
)
Текстовые кодировки
Хотелось бы еще сказать несколько слов про кодировки в xml. Редко, но все же иногда вы можете столкнуться с кодировкой, отличной от UTF-8. На этот случай вы можете задать нужную кодировку с помощью поля CharsetReader у декодера, которое является функцией и ожидается, что будет конвертировать из кодировки xml файла в utf-8 (сигнатура: ‘CharsetReader func(charset string, input io.Reader) (io.Reader, error)’ )
Самый простой вариант задать CharsetEncoder – это использование NewReaderLabel из пакета x/net/html/charset. По переданному charset (он же label в сигнатуре NewReaderLabel) с помощью метода Lookup он находит соответствие кодировке из этой таблицы. Передаваемый параметр charset берется из encoding параметра xml файла. Код будет примерно такой:
filmsDB := new(FilmsDB)
r := bytes.NewReader([]byte(data))
d := xml.NewDecoder(r)
d.CharsetReader = charset.NewReaderLabel
err := d.Decode(&filmsDB)
if err != nil {
fmt.Printf("error: %v", err)
return
}
Полный код под катом, а запустить можно по ссылке. Обратите внимание, что задан ‘encoding=»windows-1251″‘ у XML и title в кодировке windows-1251.
Работа с кодировками XML в Golang
package main
import (
"bytes"
"encoding/xml"
"fmt"
"time"
"golang.org/x/net/html/charset"
)
type userDate time.Time
const userDateFormat = "2006-01-02"
type FilmsDB struct {
XMLName xml.Name `xml:"films"`
Film []Film `xml:"film"`
}
type Film struct {
Title string `xml:"title"`
ReleaseDate userDate `xml:"releaseDate"`
}
func (ud *userDate) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
dateString := ""
err := d.DecodeElement(&dateString, &start)
if err != nil {
return err
}
dat, err := time.Parse(userDateFormat, dateString)
if err != nil {
return err
}
*ud = userDate(dat)
return nil
}
func (ud userDate) String() string {
return time.Time(ud).Format(time.RFC822)
}
func main() {
filmsDB := new(FilmsDB)
r := bytes.NewReader([]byte(data))
d := xml.NewDecoder(r)
d.CharsetReader = charset.NewReaderLabel
err := d.Decode(&filmsDB)
if err != nil {
fmt.Printf("error: %v", err)
return
}
fmt.Printf("--- Unmarshal ---\n\n")
for _, film := range filmsDB.Film {
fmt.Printf("Title: %s\n", film.Title)
fmt.Printf("Release Date: %s\n", film.ReleaseDate)
fmt.Printf("---\n")
}
}
var (
jhonnyMnemonicASCII = []byte{0xc4, 0xe6, 0xee, 0xed, 0xed, 0xe8, 0x2d, 0xcc, 0xed, 0xe5, 0xec, 0xee, 0xed, 0xe8, 0xea}
)
var (
data = `
<?xml version="1.0" encoding="windows-1251"?>
<films>
<film>
<title>` + string(jhonnyMnemonicASCII) + `</title>
<releaseDate>1995-05-26</releaseDate>
</film>
</films>
`
)
Заключение
В статье я постарался рассмотреть основные способы парсинга xml и некоторые сопутствующие вопросы. Она не претендует на полноту и не является всеобъемлющей, но этого, обычно, оказывается вполне достаточно, чтобы решить большую часть типовых задач. Надеюсь, что данные примеры немного упростят кому-нибудь жизнь и ускорят вашу разработку. В следующем разделе оставлю некоторые полезные ссылки.
Полезные ссылки
https://pkg.go.dev/encoding/xml#Marshal — документация по методу Marshal, здесь можно почитать как описывать go структуры для xml
https://www.digitalocean.com/community/tutorials/how-to-use-struct-tags-in-go-ru — про теги структур в Golang
https://blog.kowalczyk.info/tools/xmltogo/ — онлайн генератор go структур по xml файлу
https://habr.com/ru/company/vk/blog/463063/ — хорошая статья про интерфейсы в общем и про пустой интерфейс в частности
Проблема кодировок часто возникает при написании парсеров, чтении данных из 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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import ( | |
| «fmt» | |
| «golang.org/x/text/encoding/charmap» | |
| ) | |
| func main() { | |
| for i := 0; i <= 255; i++ { | |
| charnum := uint8(i) | |
| orig := []uint8{charnum} | |
| utf8 := DecodeWindows1251(orig) | |
| win1251 := EncodeWindows1251(utf8) | |
| if string(orig) != string(win1251) { | |
| fmt.Printf(«Oh~.. Failed at charnum 0x%x\n«, i) | |
| fmt.Printf(«(orig, utf8, win1251)\n«) | |
| fmt.Printf(«string: %s, %s, %s\n«, string(orig), string(utf8), string(win1251)) | |
| fmt.Printf(«quoted: %+q, %+q, %+q\n«, string(orig), string(utf8), string(win1251)) | |
| fmt.Printf(«hex : % x, % x, % x\n«, string(orig), string(utf8), string(win1251)) | |
| } | |
| } | |
| } | |
| func DecodeWindows1251(ba []uint8) []uint8 { | |
| dec := charmap.Windows1251.NewDecoder() | |
| out, _ := dec.Bytes(ba) | |
| return out | |
| } | |
| func EncodeWindows1251(ba []uint8) []uint8 { | |
| enc := charmap.Windows1251.NewEncoder() | |
| out, _ := enc.String(string(ba)) | |
| return []uint8(out) | |
| } |
Всегда нужно быть готовым к тому, что кодировка входных данных из разных источников может различаться. Конечно, большинство используют операционную систему Windows, но не только. Go по умолчанию предполагает, что строки в программах будут в кодировке UTF-8. Если это не так, тогда их требуется декодировать, чтобы в дальнейшем можно было с ними работать. В данной инструкции показано, как читать и записывать файлы в других кодировках, помимо UTF-8.
Как использовать разные кодировками в Golang?
1. Создайте файл charset.go со следующим содержимым:
Премиум 👑 канал по Golang
Рекомендуем вам супер TELEGRAM канал по Golang где собраны все материалы для качественного изучения языка. Удивите всех своими знаниями на собеседовании! 😎
Подписаться на канал
Уроки, статьи и Видео
Мы публикуем в паблике ВК и Telegram качественные обучающие материалы для быстрого изучения Go. Подпишитесь на нас в ВК и в Telegram. Поддержите сообщество Go программистов.
Go в ВК
ЧАТ в Telegram
|
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 |
package main import ( «fmt» «io/ioutil» «os» «golang.org/x/text/encoding/charmap» ) func main() { // Запись строки в кодировке Windows-1252 encoder := charmap.Windows1252.NewEncoder() s, e := encoder.String(«This is sample text with runes Š») if e != nil { panic(e) } ioutil.WriteFile(«example.txt», []byte(s), os.ModePerm) // Декодировка в UTF-8 f, e := os.Open(«example.txt») if e != nil { panic(e) } defer f.Close() decoder := charmap.Windows1252.NewDecoder() reader := decoder.Reader(f) b, err := ioutil.ReadAll(reader) if err != nil { panic(err) } fmt.Println(string(b)) } |
2. Запустите код через go run charset.go;
3. Посмотрите на результат в терминале:
|
This is sample text with runes Š |
Конвертирование кодировки Windows-1251 в UTF-8
Пакет golang.org/x/text/encoding/charmap содержит константы типа указателя Charmap, что представляют наиболее часто используемые кодировки. Тип Charmap предоставляет методы для создания кодера и декодера для определенного набора символов. Encoder создает Writer для кодировки, что кодирует записанные байты в выбранную кодировку. Также Decoder может создать Reader для декодировки, что декодирует все данные для чтения из выбранной кодировки.
Также можете ознакомиться с инструкцией для изменения кодировки строки, символы которой не относятся к Unicode.
Администрирую данный сайт с целью распространения как можно большего объема обучающего материала для языка программирования Go. В IT с 2008 года, с тех пор изучаю и применяю интересующие меня технологии. Проявляю огромный интерес к машинному обучению и анализу данных.
E-mail: vasile.buldumac@ati.utm.md
Образование
Технический Университет Молдовы (utm.md), Факультет Вычислительной Техники, Информатики и Микроэлектроники
- 2014 — 2018 Universitatea Tehnică a Moldovei, ИТ-Инженер. Тема дипломной работы «Автоматизация покупки и продажи криптовалюты используя технический анализ»
- 2018 — 2020 Universitatea Tehnică a Moldovei, Магистр, Магистерская диссертация «Идентификация человека в киберпространстве по фотографии лица»
3.3
3
голоса
Рейтинг статьи
Межтекстовые Отзывы
Посмотреть все комментарии
