Java: Экранирующие последовательности
Мы хотим показать диалог Матери Драконов со своим ребенком:
- Are you hungry? - Aaaarrrgh!
Если вывести на экран строку с таким текстом:
System.out.println("- Are you hungry?- Aaaarrrgh!");
- Are you hungry?- Aaaarrrgh!
Не то, что мы хотели. Строки расположены друг за другом, а не одна ниже другой. Нам нужно как-то сказать интерпретатору «нажать на Enter» — сделать перевод строки после вопросительного знака. Это можно сделать, используя символ перевода строки: \n :
System.out.println("- Are you hungry?\n- Aaaarrrgh!");
- Are you hungry? - Aaaarrrgh!
\n — это специальный символ. В литературе его часто обозначают как LF (Line Feed). Возможно, вы сейчас подумали, что это опечатка, ведь здесь мы видим два символа \ и n , но это не так. С точки зрения компьютера — это один невидимый символ перевода строки:
// Мы это не изучали, но вы должны знать правду // Ниже код, который возвращает длину строки "a".length(); // 1 "\n".length(); // 1 . "\n\n".length(); // 2 .
Почему так сделано? \n — всего лишь способ записать символ перевода строки, но сам перевод строки по своему смыслу – это один символ, правда, невидимый.
Именно поэтому и возникла такая задача. Нужно было как-то представить его на клавиатуре. А поскольку количество знаков на клавиатуре ограничено и отдано под самые важные, то все специальные символы реализуются в виде таких обозначений.
Символ перевода строки не является чем-то специфичным для программирования. Все, кто хоть раз печатал на компьютере, использовал перевод строки, нажимая на Enter.
Во многих редакторах есть опция, позволяющая включить отображение невидимых символов. Эта опция помогает понять, где они находятся, хотя это всего лишь схематичное отображение, ведь у этих невидимых символов нет графического представления:
- Привет!¶ - О, привет!¶ - Как дела?
Устройство, которое выводит соответствующий текст, учитывает этот символ. Например, принтер при встрече с LF протаскивает бумагу вверх на одну строку, а текстовый редактор переносит весь последующий текст ниже, также на одну строку.
\n — это пример экранирующей последовательности (escape sequence). Их еще называют управляющими конструкциями. Хотя таких символов не один десяток, в программировании часто встречаются всего несколько.
Кроме перевода строки, к таким символам относятся:
- Табуляция — разрыв, получаемый при нажатии на кнопку Tab
- Возврат каретки (только в Windows)
Программистам часто нужно использовать перевод строки \n для правильного форматирования текста:
System.out.println("Gregor Clegane\nDunsen\nPolliver\nChiswyck");
На экран выведется:
Gregor Clegane Dunsen Polliver Chiswyck
Обратите внимание на следующие моменты:
- Не имеет значения, что стоит перед или после \n : символ или пустая строка. Перевод будет обнаружен и выполнен в любом случае
- Помните, что строка может содержать один символ или вообще ноль символов. А еще строка может содержать только \n . Проанализируйте следующий пример:
System.out.println("\n"); System.out.println("Dunsen");
Здесь мы сначала выводим строку «перевод строки», а потом делаем вывод обыкновенной строки. Программа выведет на экран:
Dunsen
Почему перед строкой Dunsen появилось две пустые строки, а не одна? Дело в том, что System.out.println() при выводе значения автоматически добавляет в конец символ перевода строки. Таким образом, один перевод строки мы указали явно, передав этот символ экранирующей последовательности аргументом в функцию, а второй перевод строки добавлен самой функцией автоматически. Еще пример кода:
System.out.println("Polliver"); System.out.println("Gregor Clegane"); System.out.println(); System.out.println("Chiswyck\n"); System.out.println("Dunsen");
Вывод будет таким:
Polliver Gregor Clegane Chiswyck Dunsen
System.out.println("Joffrey loves using \\n");
на экран выйдет:
Joffrey loves using \n
Небольшое, но важное замечание про Windows. В Windows для перевода строк по умолчанию используется \r\n — это связано с историческими причинами. Такая комбинация хорошо работает только в Windows, но создает проблемы при переносе в другие системы: например, когда в команде разработчиков есть пользователи как Windows, так и Linux.
Дело в том, что последовательность \r\n имеет разную трактовку в зависимости от выбранной кодировки. Поэтому в среде разработчиков принято всегда использовать \n без \r , так как LF всегда трактуется одинаково и отлично работает в любой системе. Не забудьте настроить ваш редактор на использование \n .
Задание
Напишите программу, которая выводит на экран:
- Did Joffrey agree? - He did. He also said "I love using \n".
При этом программа использует только один System.out.println() , но результат на экране должен выглядеть в точности как показано выше.
Упражнение не проходит проверку — что делать?
Если вы зашли в тупик, то самое время задать вопрос в «Обсуждениях». Как правильно задать вопрос:
- Обязательно приложите вывод тестов, без него практически невозможно понять что не так, даже если вы покажете свой код. Программисты плохо исполняют код в голове, но по полученной ошибке почти всегда понятно, куда смотреть.
В моей среде код работает, а здесь нет
Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.
Мой код отличается от решения учителя
Это нормально , в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи.
В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.
Прочитал урок — ничего не понятно
Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в «Обсуждениях». Идеально, если вы сформулируете непонятные моменты в виде вопросов. Обычно нам нужно несколько дней для внесения правок.
Кстати, вы тоже можете участвовать в улучшении курсов: внизу есть ссылка на исходный код уроков, который можно править прямо из браузера.
Полезное
Экранирование, специальные символы
Как мы уже видели, обратная косая черта \ используется для обозначения классов символов, например \d . Это специальный символ в регулярных выражениях (как и в обычных строках).
Есть и другие специальные символы, которые имеют особое значение в регулярном выражении. Они используются для более сложных поисковых конструкций. Вот полный перечень этих символов: [ ] \ ^ $ . | ? * + ( ) .
Не надо пытаться запомнить этот список: мы разберёмся с каждым из них по отдельности, и таким образом вы выучите их «автоматически».
Экранирование символов
Допустим, мы хотим найти буквально точку. Не «любой символ», а именно точку.
Чтобы использовать специальный символ как обычный, добавьте к нему обратную косую черту: \. .
Это называется «экранирование символа».
alert( "Глава 5.1".match(/\d\.\d/) ); // 5.1 (совпадение!) alert( "Глава 511".match(/\d\.\d/) ); // null ("\." - ищет обычную точку)
Круглые скобки также являются специальными символами, поэтому, если нам нужно использовать именно их, нужно указать \( . В приведённом ниже примере ищется строка «g()» :
alert( "function g()".match(/g\(\)/) ); // "g()"
Если мы ищем обратную косую черту \ , это специальный символ как в обычных строках, так и в регулярных выражениях, поэтому мы должны удвоить её.
alert( "1\\2".match(/\\/) ); // '\'
Косая черта
Символ косой черты ‘/’ , так называемый «слэш», не является специальным символом, но в JavaScript он используется для открытия и закрытия регулярного выражения: /. шаблон. / , поэтому мы должны экранировать его.
Вот как выглядит поиск самой косой черты ‘/’ :
alert( "/".match(/\//) ); // '/'
С другой стороны, если мы не используем короткую запись /. / , а создаём регулярное выражение, используя new RegExp , тогда нам не нужно экранировать косую черту:
alert( "/".match(new RegExp("/")) ); // находит /
new RegExp
Если мы создаём регулярное выражение с помощью new RegExp , то нам не нужно учитывать / , но нужно другое экранирование.
Например, такой поиск не работает:
let regexp = new RegExp("\d\.\d"); alert( "Глава 5.1".match(regexp) ); // null
Аналогичный поиск в примере выше с /\d\.\d/ вполне работал, почему же не работает new RegExp(«\d\.\d») ?
Причина в том, что символы обратной косой черты «съедаются» строкой. Как вы помните, обычные строки имеют свои специальные символы, такие как \n , и для экранирования используется обратная косая черта.
Вот как воспринимается строка «\d.\d»:
alert("\d\.\d"); // d.d
Строковые кавычки «съедают» символы обратной косой черты для себя, например:
- \n – становится символом перевода строки,
- \u1234 – становится символом Юникода с указанным номером,
- …А когда нет особого значения: как например для \d или \z , обратная косая черта просто удаляется.
Таким образом, new RegExp получает строку без обратной косой черты. Вот почему поиск не работает!
Чтобы исправить это, нам нужно удвоить обратную косую черту, потому что строковые кавычки превращают \\ в \ :
let regStr = "\\d\\.\\d"; alert(regStr); // \d\.\d (теперь правильно) let regexp = new RegExp(regStr); alert( "Глава 5.1".match(regexp) ); // 5.1
Итого
- Для поиска специальных символов [ ] \ ^ $ . | ? * + ( ) , нам нужно добавить перед ними \ («экранировать их»).
- Нам также нужно экранировать / , если мы используем /. / (но не new RegExp ).
- При передаче строки в new RegExp нужно удваивать обратную косую черту: \\ для экранирования специальных символов, потому что строковые кавычки «съедят» одну черту.
Шаблонные строки
Шаблонными литералами называются строковые литералы, допускающие использование выражений внутри. С ними вы можете использовать многострочные литералы и строковую интерполяцию. В спецификациях до ES2015 они назывались «шаблонными строками».
Синтаксис
`строка текста` `строка текста 1 строка текста 2` `строка текста $ строка текста` tag `строка текста $ строка текста`
Описание
Шаблонные литералы заключены в обратные кавычки (` `) вместо двойных или одинарных. Они могут содержать подстановки, обозначаемые знаком доллара и фигурными скобками ( $ ). Выражения в подстановках и текст между ними передаются в функцию. По умолчанию функция просто объединяет все части в строку. Если перед строкой есть выражение (здесь это tag ), то шаблонная строка называется «теговым шаблоном». В этом случае, теговое выражение (обычно функция) вызывается с обработанным шаблонным литералом, который вы можете изменить перед выводом. Для экранирования обратной кавычки в шаблонных литералах указывается обратный слеш \.
`\`` === "`"; // --> true
Многострочные литералы
Символы новой строки являются частью шаблонных литералов. Используя обычные строки, вставка переноса потребовала бы следующего синтаксиса:
.log("string text line 1\n" + "string text line 2"); // "string text line 1 // string text line 2"
То же с использованием шаблонных литералов:
.log(`string text line 1 string text line 2`); // "string text line 1 // string text line 2"
Интерполяция выражений
Для вставки выражений в обычные строки вам пришлось бы использовать следующий синтаксис:
var a = 5; var b = 10; console.log("Fifteen is " + (a + b) + " and not " + (2 * a + b) + "."); // "Fifteen is 15 and not 20."
Теперь, при помощи шаблонных литералов, вам доступен «синтаксический сахар», делающий подстановки вроде той более читабельными:
var a = 5; var b = 10; console.log(`Fifteen is $a + b> and not $2 * a + b>.`); // "Fifteen is 15 and not 20."
Вложенные шаблоны
Временами, вложить шаблон — это кратчайший и, возможно, более читабельный способ составить строку. Просто поместите внутрь шаблона с обратными кавычками ещё одни, обернув их в подстановку $ < >. Например, если выражение истинно, можно вернуть шаблонный литерал.
var classes = "header"; classes += isLargeScreen() ? "" : item.isCollapsed ? " icon-expander" : " icon-collapser";
В ES2015 с шаблонными литералами без вложения:
const classes = `header $ isLargeScreen() ? "" : item.isCollapsed ? "icon-expander" : "icon-collapser" >`;
В ES2015 с вложенными шаблонными литералами:
const classes = `header $ isLargeScreen() ? "" : `icon-$item.isCollapsed ? "expander" : "collapser">` >`;
Теговые шаблоны
Расширенной формой шаблонных литералов являются теговые шаблоны. Они позволяют разбирать шаблонные литералы с помощью функции. Первый аргумент такой функции содержит массив строковых значений, а остальные содержат выражения из подстановок. В итоге, функция должна вернуть собранную строку (или что-либо совсем иное, как будет показано далее). Имя функции может быть любым.
var person = "Mike"; var age = 28; function myTag(strings, personExp, ageExp) var str0 = strings[0]; // "That " var str1 = strings[1]; // " is a " // Технически, в конце итогового выражения // (в нашем примере) есть ещё одна строка, // но она пустая (""), так что пропустим её. // var str2 = strings[2]; var ageStr; if (ageExp > 99) ageStr = "centenarian"; > else ageStr = "youngster"; > // Мы даже можем вернуть строку, построенную другим шаблонным литералом return `$str0>$personExp>$str1>$ageStr>`; > var output = myTag`That $person> is a $age>`; console.log(output); // That Mike is a youngster
Функция тега не обязана возвращать строку, как показано в примере ниже:
function template(strings, . keys) return function (. values) var dict = values[values.length - 1] || >; var result = [strings[0]]; keys.forEach(function (key, i) var value = Number.isInteger(key) ? values[key] : dict[key]; result.push(value, strings[i + 1]); >); return result.join(""); >; > var t1Closure = template`$0>$1>$0>!`; t1Closure("Y", "A"); // "YAY!" var t2Closure = template`$0> $"foo">!`; t2Closure("Hello", foo: "World" >); // "Hello World!"
Сырые строки
Специальное свойство raw , доступное для первого аргумента тегового шаблона, позволяет получить строку в том виде, в каком она была введена, без экранирования.
function tag(strings) return strings.raw[0]; > tag`string text line 1 \\n string text line 2`; // выводит "string text line 1 \\n string text line 2", // включая 'n' и два символа '\'
Вдобавок, существует метод String.raw() , возвращающий точно такую же исходную строку, какую вернула бы функция шаблона по умолчанию и строковая конкатенация вместе.
var str = String.raw`Hi\n$2 + 3>!`; // "Hi\n5!" str.length; // 6 str.split("").join(","); // "H,i,\,n,5,!"
Теговые шаблоны и экранирование символов
Поведение в ES2016
В ECMAScript 2016 теговые шаблоны следуют правилам экранирования следующих символов:
- символы Unicode, начинающиеся с «\u», например, \u00A9
- точки кода Unicode, начинающиеся с «\u<>«, например, \u
- шестнадцатеричные представления символов, начинающиеся с «\x», например, \xA9
- восьмеричные представления символов, начинающиеся с «\», например, \251
Отсюда вытекает проблема теговых шаблонов: следуя грамматике ECMAScript, анализатор кода, найдя символ \ , будет искать корректное представление символа Unicode, но может не найти его вовсе. Пример ниже показывает это:
`\unicode`; // В старых версиях ECMAScript (ES2016 и раньше) выкинет исключение: // SyntaxError: malformed Unicode character escape sequence
Поведение в ES2018
Теговые шаблоны должны позволять встраивать языки (например, DSLs или LaTeX), в которых широко используются многие другие экранирования. Предложение Редакция шаблонных литералов (уровень 4, одобренный к добавлению в стандарт ECMAScript 2018) устраняет синтаксические ограничения экранирования теговых шаблонов в ECMAScript.
Однако, некорректное экранирование символов по-прежнему нужно отображать в «приготовленном» отображении. Оно показывается в виде undefined в «приготовленном» массиве:
function latex(str) return cooked: str[0], raw: str.raw[0] >; > latex`\unicode`; //
Заметьте, что ограничение на экранирование символов проявляется лишь в теговых шаблонах, и не проявляется в нетеговых шаблонных литералах:
let bad = `bad escape sequence: \unicode`;
Спецификации
| Specification |
|---|
| ECMAScript Language Specification # sec-template-literals |
Совместимость с браузерами
BCD tables only load in the browser
Смотрите также
- String
- String.raw()
- Лексическая грамматика
- Подобные шаблонам строки в ES3-совместимом синтаксисе
- ES6 в деталях: шаблонные строки
Found a content problem with this page?
- Edit the page on GitHub.
- Report the content issue.
- View the source on GitHub.
This page was last modified on 16 нояб. 2023 г. by MDN contributors.
Your blueprint for a better internet.
MDN
Support
- Product help
- Report an issue
Our communities
Developers
- Web Technologies
- Learn Web Development
- MDN Plus
- Hacks Blog
- Website Privacy Notice
- Cookies
- Legal
- Community Participation Guidelines
Visit Mozilla Corporation’s not-for-profit parent, the Mozilla Foundation.
Portions of this content are ©1998– 2024 by individual mozilla.org contributors. Content available under a Creative Commons license.
Программирование Java 1
если вам нужно помощь в установке нужного софта, вот ссылки на гайды:
- Скоро здесь появится ссылка.
Также я упоминал еще одно странное слово JRE (Java Runtime Environment — среда выполнения java) — это среда для выполнения программ на Java.
Если вы скачали и установили JDK, в него входит и среда выполнения, скачивать больше ничего не нужно.
А где мы будем писать код?
Можно конечно в блокнотике, но я не думаю, что это хорошая идея. Существует большое множество текстовых редакторов и IDE. Если с текстовыми редактором все понятно — программа для редактирования текста, то IDE — это Integrated development environment, интегрированная среда разработки — программа в которой встроено множество функций для разработки и сам редактор. Более подробно про IDE и текстовые редакторы вы можете прочитать здесь:
- Скоро здесь появится ссылка.
P.S. Если вы не хотите тратить время на статью про IDE и текстовых редакторах, вкратце — Для Java советую использовать Intelij IDE (устанавливайте community версию — она бесплатна), также многие используют NetBeans IDE , Eclipse IDE. Если вам достаточно текстового редактора рекомендую Sublime Text , Visual Studio Code , Atom.
Надеюсь, что на этом этапе вы уже установили и настроили все не обходимое для разработки. Мы приступаем к изучению самого языка.
По традиции первая программа представляет из себя вывод на экран надпись «Hello world!».
Если вы работаете в intelij IDE нажмите ПКМ во вкладе с деревом проекта -> по папке src. В контекстном меню выберите New -> класс Java.