Экранирование символов

Открыта

Квест Java Syntax Pro еще в разработке

Сейчас мы вычитываем лекции и работаем над задачами. Если заметили ошибки — пишите в комментариях: всё учтем перед релизом. Спасибо!

1. Причины возникновения экранирования символов

Когда-то давно вы узнали, что чтобы записать в коде строку символов, нужно обернуть эти символы в двойные кавычки: получится строковой литерал.

А что делать, если нам нужно, чтобы кавычки были внутри строкового литерала? Строка, содержащая кавычки — что может быть проще.

Допустим, мы хотим вывести текст Фильм "Друзья" номинирован на "Оскар". Как это сделать?

Код Примечания
String s = "Фильм "Друзья" номинирован на "Оскар"";
Этот вариант работать не будет!

Все дело в том, что по мнению компилятора тут записан совсем другой код:

Код Примечания
String s = "Фильм "Друзья" номинирован на "Оскар"";
Этот вариант работать не будет!

После того, как компилятор встретит двойные кавычки в коде, он будет считать их началом строкового литерала. Следующие двойные кавычки — окончанием строкового литерала.

Так как же записать в двойные кавычки внутри литерала?


2. Экранирование символов

Способ есть, ему даже дали название — экранирование символов. Вы просто пишете внутри строки текста кавычки, а перед кавычками добавляете символ \ (обратная косая черта или обратный слеш или бекслеш, от англ. backslash).

Вот как будет выглядеть правильно записанный строковой литерал:

Код Примечания
String s = "Фильм \"Друзья\" номинирован на \"Оскар\"";
Это сработает!

Компилятор все поймет правильно и не будет считать кавычки, расположенные после обратной косой черты, обычными кавычками.

Более того, если вывести данную строку на экран, кавычки с обратной косой чертой будут правильно обработаны, и на экран будет выведена надпись без обратной косой черты: Фильм "Друзья" номинирован на "Оскар"

Еще важный момент. Кавычки, предваренные обратной косой чертой — это один символ: мы просто пользуемся таким хитрым способом записи, чтобы не мешать компилятору распознавать строковые литералы в коде. Вы можете присвоить кавычки в переменную char:

Код Примечания
char c = '\"';
\" — это один символ, а не два
char c = '"';
так тоже можно: двойная кавычка внутри одинарных кавычек

3. Часто возникающие ситуации при экранировании символов

Часто возникающие ситуации экранирования символов

Кроме двойных кавычек, есть еще много символов, которые по-особому обрабатываются компилятором. Например, перенос строки.

Как добавить в литерал перенос строки? Для этого тоже есть специальная комбинация:

\n
Символ переноса строки

Если вы хотите добавить в строковой литерал перенос строки, вам нужно просто добавить пару символов – \n.

Пример:

Код Вывод на экран
System.out.println("С уважением,\nАноним");
С уважением,
Аноним

Всего таких специальных комбинаций 8: их еще называют escape-последовательностями, вот они:

Код Описание
\t Вставить символ табуляции
\b Вставить символ возврата на один символ
\n Вставить символ новой строки
\r Вставить символ возврата каретки
\f Вставить символ прогона страницы
\' Вставить одинарную кавычку
\" Вставить двойную кавычку
\\ Вставить обратный слеш

С двумя из них вы познакомились, а что значат остальные 6?

Символ табуляции – \t

Данный символ в тексте эквивалентен нажатию на клавиатуре клавиши Tab при наборе текста. Он сдвигает следующий за ним текст с целью его выровнять.

Пример:

Код Вывод на экран
System.out.println("0\t1\t2\t3");
System.out.println("0\t10\t20\t30");
System.out.println("0\t100\t200\t300");
0       1        2        3
0       10       20       30
0       100      200      300

Возврат на один символ назад – \b

Данный символ в тексте эквивалентен нажатию на клавиатуре клавиши Backspace при наборе текста. Он удаляет последний выведенный символ перед ним:

Код Вывод на экран
System.out.println("Привет\b\b Мир");
Прив Мир!

Символ возврата каретки – \r

Этот символ переносит курсор в начало текущей строки, не меняя текста. Следующий выводимый текст будет перетирать существующий.

Пример:

Код Вывод на экран
System.out.println("Привет\rМир!");
Мир!ет

Символ прогона страницы – \f

Это символ дошел до нас из эпохи первых матричных принтеров. Если подать такой символ на печать, это приводило к тому, что принтер просто прокручивал текущий лист, не печатая текст, пока не начнется новый.

Сейчас бы мы назвали его разрыв страницы или новая страница.

Обратный слэш – \\

Ну а тут вообще все просто. Если мы используем обратную косую черту (обратный слэш) в тексте, чтобы экранировать символы, то как тогда записать в текстовой строке сам символ косой черты?

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

Пример:

Код Вывод на экран
System.out.println("c:\projects\my\first");
Компилятор будет ругаться на неизвестные экранированные символы.
System.out.println("c:\\projects\\my\\first");
Вот так правильно!


4. Кодировка Unicode

Как вы уже знаете, каждому символу, отображаемому на экране, соответствует определенный числовой код. Стандартизированный набор таких кодов называют кодировкой.

Когда-то давно, когда только изобрели компьютеры, для кодировки всех символов было достаточно семи бит (меньше одного байта) – первая кодировка содержала всего 128 символов. Называлась такая кодировка ASCII.

ASCII (англ. American Standard Code for Information Interchange) — американская стандартная кодировочная таблица для печатных символов и некоторых специальных кодов.

Она состояла из 33 непечатных управляющих символов (влияющих на обработку текста и пробелов) и 95 печатных символов, включая цифры, буквы латинского алфавита в строчном и прописном вариантах и ряд пунктуационных символов.

Кодировка Unicode

Рост популярности компьютеров привел к тому, что каждая страна начала выпускать свою кодировку. Обычно за основу брали ASCII и заменяли редко используемые символы на символы национальных алфавитов.

Со временем появилась идея: создать одну кодировку, в которой разместить все символы всех мировых кодировок.

Кодировка Unicode 1

В 1993 году была создана кодировка Unicode, и язык Java был первым языком программирования, который использовал ее как стандарт хранения текста. Сейчас же Unicode — стандарт всей ИТ-индустрии.

И хотя Unicode сам по себе является стандартом, у него есть несколько форм представления (Unicode transformation format, UTF): UTF-8, UTF-16 и UTF-32, и пр.

В Java используется продвинутая разновидность кодировки Unicode – UTF-16: каждый символ в которой кодировался 16 битами (2 байтами). Она способна вместить до 65,536 символов!

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

Чтобы записать в коде программы символ кодировки Unicode по его коду, нужно написать \u + шестнадцатеричные цифры кода. Например \u00A9

Код Вывод на экран
System.out.println("\u00A9 JavaRush");
© JavaRush


5. Unicode: codepoint

640 Килобайт хватит всем! Или нет. (Цитата, приписываемая Биллу Гейтсу)

Жизнь — суровая штука, и кодировки UTF-16 со временем стало не хватать. Оказалось, что в Азии очень много языков, а у них очень много иероглифов. И все иероглифы просто невозможно засунуть в 2 байта.

И что же делать? Использовать больше байт!

Вот только тип char занимает всего 2 байта и поменять его на 4 не так просто: в мире написаны миллиарды строк кода на Java, которые будут работать неправильно, если вдруг в Java-машине тип char станет 4 байта. Так что менять тип char нельзя!

Есть и другой подход. Вспомните, как мы экранировали символы с помощью префикса в виде косой черты. Мы, по сути, кодировали один символ с помощью нескольких символов.

Этот же подход решили использовать и разработчики Java.

Некоторые символы, которые визуально выглядят как один символ, в строке кодируются двумя char'ами:

Код Вывод на экран
System.out.println("\uD83D\uDD0A");
🔊

Теперь ваша программа на Java может выводить в консоль даже emoji 😎


Комментарии (10)
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий вы должны авторизоваться
sergey-sy 19 уровень, Москва
12 сентября 2020, 22:26
Но вот если ей не хватает места для выравнивания, то тогда фигачит 4 пробела.
sergey-sy 19 уровень, Москва
12 сентября 2020, 22:23
Для меня удивительно, что табуляция реально выравнивает текст. Я предпологал, что она просто будет 4 пробела пихать.
Dima Pyshinsky 17 уровень, Москва
6 мая 2020, 17:06
Обратите внимание на то, что символ переноса строки отстоит от слова "Аноним" на один пробел, а в выводе этого пробела нет.
System.out.println("С уважением, \n Аноним");
//Вывод у данного кода должен быть таким:
//С уважением,
// Аноним
LEONID ZHIKHARSKIY 1 уровень
16 апреля 2020, 14:20
Не понятно зачем два слеша после Привет? System.out.println("Привет\\b\b Мир");
Александр 24 уровень, Могилев
27 апреля 2020, 15:51
Все очень просто - первый обратный слеш экранирует второй обратный слеш, а потом комбинация \b стирает первый символ b, оставляя тем самым в тексте после слова "Привет" обратный слеш. Суть проста ))
Eugene Tukalau 23 уровень, Новополоцк
11 июня 2020, 12:05
А я думаю, вы поавильно заметили, это опечатка. Потому, что когда я скомпилировал это, с из выводом не совпало. Должно быть "Привет\b\b Мир!"; Для их вывода.
Andrei Po 29 уровень
7 октября 2020, 16:02
System.out.println("Привет\b\b Мир!"); - даёт вывод Прив Мир! Ответ Александра - правильный. (в JVM на Windows. в других OS - могут быть нюансы).
BariO 16 уровень, Nizhniy Novgorod
5 марта 2020, 15:22
Этот символ переносит курсор в начало текущей строки, не меняя текста. Следующий выводимый текст будет перетирать существующий. Пример:
System.out.println("Привет\\r Мир!");
Мир!
текст то мы все равно поменяли. в чем тогда смысла сохранения текста до того как начнем вводить что-то новое
Анатолий 4 уровень
18 апреля 2020, 22:01
Пример, как мне кажется, притянут за уши, но вот совместно с Thread.sleep() можно в консоли сделать бегущую строку.
Дмитрий 30 уровень
1 февраля 2020, 19:32
Ошибки в примерах. Первый слеш - лишний.
System.out.println("Привет\\b\b Мир");
В консоли будет
Привет\ Мир
И тут тоже
System.out.println("Привет\\r Мир!");
В консоли будет
Привет\r Мир