строки в golang

После изучения данной статьи вы сможете:

  • Получить доступ к отдельным буквам, а также манипулировать ими;
  • Зашифровать и расшифровать сообщение;
  • Написать программу для людей, что говорят на разных языках.

С самого начала изучения программирования при наборе простого кода «Hello, playground» вы уже задействовали текст. Буквы, цифры и различные знаки называют символами (characters). Символы, помещенные между кавычками, называют строковым литералом (literal string).

Форум Гоферов

Мы работаем над форумом для программистов на Golang. Очень нужны модераторы которые хотят помочь с ответами для новичков и помочь в развитии Go-сообщества.

Go на Форум

Уроки, статьи и Видео

Мы публикуем в паблике ВК и Telegram качественные обучающие материалы для быстрого изучения Go. Подпишитесь на нас в ВК и в Telegram. Поддержите сообщество Go программистов.

Go в ВК Go в Telegram

Содержание статьи

Наверняка вам известно, что компьютеры оперируют через нули и единицы. Будучи компьютером, как бы вы переписали алфавит, а заодно и человеческий язык? С помощью цифр, верно. У символов алфавита есть цифровые значения, следовательно, ими можно манипулировать как числами.

Однако, все не так просто. У многих языков есть уникальные знаки, плюс ко всему к тысячам символов добавляются многочисленные эмодзи. В Go есть свои способы представления текста в наиболее удобном и простом виде.

Объявление строковых переменных Go

Литеральные значения, помещенные в кавычки, относятся к типу string. Следующие три строки кода эквивалентны:

При объявлении переменной без указания значения она будет инициализирована с нулевым значением. Нулевым значением типа string являются пустые кавычки (""):

Необработанные строковые литералы Golang

В строковых литералах могут находиться специальные экранированные символы наподобие \n. Во избежание замены \n новой строкой можно поместить текст в обратные кавычки ` вместо обычных ", как показано в примере ниже. Обратные кавычки выводят строку в необработанном виде.

Вывод предыдущего листинга:

В отличие от обычных литеральных строк необработанные строки могут охватывать несколько строк исходного кода, как показано в примере ниже:

Результат листинга 2, включая отступы:

Как строковые литералы, так и необработанные строковые литералы выводят данные типа string, как показано в примере ниже.

Вопрос для проверки:

Для пути Windows C:\go лучше использовать строковой литерал или необработанный строковой литерал? Почему?

Символы, коды, rune и byte

Unicode Consortium присваивает числовые значения, или коды, более миллиону уникальных символов. К примеру, 65 является кодом заглавной буквы А, а 1285515 — смайлика 😃.

Для представления Юникода в Go используется тип rune, который иначе называется int32.

byte является другим названием типа uint8. Он используется для бинарных данных, хотя byte может использоваться для символа английского алфавита, определенного ASCII, более старого 128-символьного набора Юникод.

Разные названия одного типа: В Go у одного и того же типа могут быть разные названия. К примеру, rune и int32 являются взаимозаменяемыми. Хотя byte и rune были в Go с самого начала, с появлением версии Go 1.9 стало возможным объявлять свои собственные названия типов. Синтаксис выглядит следующим образом:

Оба byte и rune ведут себя также, как и типы целых чисел, другими названиями которых они являются. Это показано в следующем листинге:

Для отображения символов вместо их числовых значений можно использовать специальный символ %c вместе с Printf:

Вместе с будет работать любой целочисленный тип, однако название rune является своеобразной подсказкой, что число 960 на самом деле является каким-то символом.

Запоминать все Юникоды нет нужды, в Go есть символьный литерал. Просто поместите символ в одинарные кавычки: 'A'. Если тип не уточняется, Go присвоит тип rune. Следующие три строки кода эквиваленты:

Переменная grade по-прежнему содержит числовое значение, в данном случае 65, то есть код для заглавной буквы 'A'. Символьные литералы также можно использовать для типа с названием byte:

Вопросы для проверки:

  1. Сколько символов кодирует ASCII?
  2. Другим названием какого типа является byte? А rune?
  3. Какой код используется для звездочки *, смайлика 😃 и буквы е со знаком ударения é?

Можно ли изменять строки в Golang?

Строки в Golang не предназначены для манипуляции. Переменной можно присвоить другую строку, однако строки сами по себе редактировать нельзя:

Программа может получить доступ к отдельным символам, но не может редактировать саму строку. В следующем листинге используются квадратные скобки [] для уточнения индекса внутри строки, что обращается к одному байту (символ ASCII). Индексы начинаются с нуля.

Строки Go неизменны, их также нельзя менять в таких языках, как Python, Java и JavaScript. В отличие от строк в Ruby и массивов символов в С, строку в Go отредактировать нельзя:

Задание для проверки:

Напишите программу для вывода каждого байта (символ ASCII) слова «shalom», по одному символу на строку.

Манипуляция символами с помощью шифра Цезаря

Эффективным методом отправки секретных сообщений во втором веке был сдвиг букв. Таким образом, a становится d, b становится e и так далее. В результате получается странный текст, будто написанный на иностранном языке: L fdph, L vdz, L frqtxhuhg. 

Как оказалось, манипуляция символами как цифровыми значениями дается компьютерам очень легко. Это показано в коде ниже:

У данного кода есть проблема. Он не подойдет для сообщений слов с буквами ‘x’, ‘y’ и ‘z’, то есть тремя последними буквами английского алфавита. Избавиться от данного неудобства можно с помощью переполнения значений, то есть возврата к началу алфавита. Таким образом, ‘x’ станет ‘а’, ‘y’ станет ‘b’, а ‘z’ станет ‘c’. С 26 знаками английского алфавита это достаточно просто:

Чтобы декодировать данный шифр Цезаря, нужно убрать 3, а не добавлять. Однако в таком случае вам придется учитывать, что c < ‘a’, добавляя 26.

Вопрос для проверки:

Каким будет результат выражения c = c — ‘a’ + ‘A’, если с является 'g' в нижнем регистре?

ROT13 — современный вариант шифра Цезаря

ROT13 (rotate 13, сдвинуть на 13 позиций) является современным вариантом шифра Цезаря. С одним отличием: сдвиг происходит не на 3, а на 13 символов. Вместе с ROT13 шифрование и дешифрование становятся одинаково удобными операциями.

Предположим, что при сканировании воздушной оболочки на наличие иноземных объектов Институт SETI получил сообщение, содержание которого выглядит следующим образом:

Есть подозрение, что message на самом деле является английским текстом, зашифрованным с ROT13. Перед взломом кода вам нужно кое-что знать. Длина message составляет 30 символов, что можно определить через встроенную функцию len:

В Go есть удобные встроенные функции, которые можно использовать без оператора импорта пакетов. Функция len определяет длину различных типов. В данном случае len возвращает длину string в байтах.

Следующий листинг дешифрует сообщение из космоса. Запустите код на Go Playground и выясните, что за сообщение передают инопланетяне.

Обратите внимание, что реализация ROT13 в данном коде предназначена только для символов ASCII (байтов). Сообщение, написанное на русском или испанском, пришлось бы расшифровывать иначе. Поговорим об этом далее.

Вопросы для проверки:

  1. Для чего нужна встроенная функция len?
  2. Запустите Листинг 7 на Go Playground? Что говорится в сообщении?

Декодирование строк в руны

Строки в Go закодированы в UTF-8, одним из нескольких стандарт кодирования юникод символов. UTF-8 является эффективным кодированием переменной длины. Один код может использовать 8, 16 или 32 бита памяти. Используя кодирование переменной длины, UTF-8 делает перевод из ASCII довольно несложным, ведь символ ASCII идентичным своим зашифрованным вариантам из UTF-8.

На заметку: В Интернете UTF-8 является доминирующим стандартом кодировки. Он был введен в 1992 году Кеном Томпсоном, одним из дизайнеров Go.

Программа с ROT13 из Листинга 7 получает доступ к отдельным байтам (8-bit) строки message без подсчета символов длиной в большее количество байт (16-bit или 32-bit). Это неплохо подходит для английских символов (ASCII), но в случае русского или испанского — получается непонятная мешанина. Ты способен на лучшее, амиго.

Первым шагом на пути к поддержке других языков является декодирование символов в тип rune, что делается перед манипуляцией ими. К счастью, у Go есть функции и другие особенности языка для декодирования закодированных UTF-8 строк.

Пакет utf8 предоставляет функции для определения длины строки в рунах, а не байтах, а также декодирования первого символа строки. Функция DecodeRuneInString возвращает первый символ и количество байт, что символ тратит, как показано в Листинге 8.

На заметку: В отличие от многих других языков программирования, функции в Go могут вернуть много значений. Множественные возвращаемые значения будут подробно рассмотрены в одном из следующих уроков.

В языке Go есть ключевое слово range для итерирования разнообразных наборов. Оно также может декодировать закодированные строки UTF-8, как показано в следующем листинге.

При каждой итерации переменные i и c присваиваются текущий индекс в строке и коду (rune) на данной позиции.

Если вам не нужен индекс, пустой идентификатор (нижнее подчеркивание) позволяет проигнорировать его:

Вопросы для проверки:

  1. Сколько рун в английском алфавите "abcdefghijklmnopqrstuvwxyz"? Сколько байтов?
  2. Сколько байтов в руне '¿'?

Заключение

  • Экранированные символы вроде \n игнорируются в необработанных строковых литералах (`);
  • Строки не изменяются. К отдельным символам можно получить доступ, но изменить их нельзя;
  • Строки используют кодировку под названием UTF-8, где каждому символу требуется от 1 до 4 байтов;
  • byte является другим названием типа uint8, a rune является другим названием типа int32;
  • Ключевое слово range может декодировать закодированную строку UTF-8 в руны.

Итоговое задание для проверки #1:

Расшифруйте цитату Юлия Цезаря: L fdph, L vdz, L frqtxhuhg. 

Ваша программа должна будет сдвинуть буквы верхнего и нижнего регистра на -3. Помните, что ‘a’ становится ‘x’, ‘b’ становится ‘y’, а ‘c’ становится ‘z’. То же самое происходит с буквами верхнего регистра.

Итоговое задание для проверки #2:

Зашифруйте сообщение на испанском: “Hola Estación Espacial Internacional”  через ROT13. Модифицируйте Листинг 7 с использованием ключевого слова range. Теперь, когда вы используете ROT13 c испанским текстом, ударение над буквами сохраняется.

Понравилась статья?

Поддержи наш проект, чтобы мы могли создать больше хорошего контента!