В JavaScript текстовые данные хранятся в виде строк. Для одного символа не существует отдельного типа.
Внутренний формат строк всегда UTF-16, он не привязан к кодировке страницы.
Давайте вспомним виды цитат.
Строки могут быть заключены в одинарные, двойные кавычки или обратные кавычки:
let single = 'в одинарных кавычках'; let double = "двойные кавычки"; пусть обратные кавычки = `обратные кавычки`;
Одинарные и двойные кавычки по сути одинаковы. Однако обратные кавычки позволяют нам вставлять любое выражение в строку, заключая его в ${…}
:
функция sum(a, b) { вернуть а + б; } alert(`1 + 2 = ${sum(1, 2)}.`); // 1 + 2 = 3.
Еще одним преимуществом использования обратных кавычек является то, что они позволяют строке занимать несколько строк:
let GuestList = `Гости: * Джон * Пит * Мэри `; оповещение (список гостей); // список гостей, несколько строк
Выглядит естественно, правда? Но одинарные или двойные кавычки таким образом не работают.
Если мы воспользуемся ими и попытаемся использовать несколько строк, возникнет ошибка:
let GuestList = "Гости: // Ошибка: неожиданный токен НЕЗАКОННО * Джон";
Одинарные и двойные кавычки пришли из древних времен создания языка, когда не учитывалась необходимость многострочных строк. Обратные кавычки появились намного позже и поэтому более универсальны.
Обратные кавычки также позволяют нам указать «функцию шаблона» перед первым обратным кавычком. Синтаксис: func`string`
. Функция func
вызывается автоматически, получает строку и встроенные выражения и может их обрабатывать. Эта функция называется «шаблоны с тегами», ее редко можно увидеть, но вы можете прочитать о ней в MDN: Литералы шаблонов.
По-прежнему возможно создавать многострочные строки с одинарными и двойными кавычками, используя так называемый «символ новой строки», записанный как n
, который обозначает разрыв строки:
let GuestList = "Гости:n * Джонn * Питn * Мэри"; оповещение (список гостей); // многострочный список гостей, такой же, как и выше
В качестве более простого примера, эти две строки равны, просто написаны по-разному:
let str1 = "ПриветnМир"; // две строки с использованием «символа новой строки» // две строки с использованием обычного символа новой строки и обратных кавычек let str2 = `Привет Мир`; оповещение (str1 == str2); // истинный
Есть и другие, менее распространенные специальные символы:
Характер | Описание |
---|---|
n | Новая линия |
r | В текстовых файлах Windows комбинация двух символов rn представляет собой новый разрыв, а в ОС, отличной от Windows, это просто n . По историческим причинам большинство программ Windows также понимают n . |
' , " , ` | Кавычки |
\ | обратная косая черта |
t | Вкладка |
b , f , v | Backspace, Form Feed, Вертикальная вкладка – упомянуты для полноты, пришли из старых времен, сейчас не используются (их можно забыть прямо сейчас). |
Как видите, все специальные символы начинаются с обратной косой черты . Его еще называют «экранирующим символом».
Поскольку это особенный вариант, если нам нужно отобразить фактическую обратную косую черту внутри строки, нам нужно удвоить ее:
alert(`Обратная косая черта: \`); // Обратная косая черта:
Так называемые «экранированные» кавычки '
, "
, `
используются для вставки кавычки в строку, заключенную в те же кавычки.
Например:
alert('Я Морж!'); // Я Морж!
Как видите, нам нужно добавить обратную косую черту '
перед внутренней кавычкой, потому что в противном случае это будет означать конец строки.
Конечно, экранировать нужно только те кавычки, которые совпадают с окружающими. Итак, в качестве более элегантного решения мы могли бы вместо этого переключиться на двойные кавычки или обратные кавычки:
alert("Я Морж!"); // Я Морж!
Помимо этих специальных символов, существует также специальная нотация для кодов Юникода u…
, она используется редко и рассматривается в дополнительной главе о Юникоде.
Свойство length
имеет длину строки:
alert(`Myn`.length); // 3
Обратите внимание, что n
— это одиночный «специальный» символ, поэтому его длина действительно равна 3
.
length
- это свойство
Люди, владеющие некоторыми другими языками, иногда опечатываются, вызывая str.length()
вместо просто str.length
. Это не работает.
Обратите внимание, что str.length
— это числовое свойство, а не функция. После него скобки добавлять не нужно. Не .length()
, а .length
.
Чтобы получить символ в позиции pos
, используйте квадратные скобки [pos]
или вызовите метод str.at(pos). Первый символ начинается с нулевой позиции:
let str = `Привет`; // первый символ предупреждение (ул[0]); // Ч оповещение(str.at(0)); // Ч // последний символ предупреждение(str[str.length - 1]); // о предупреждение(str.at(-1));
Как видите, преимущество метода .at(pos)
состоит в том, что он допускает отрицательную позицию. Если pos
отрицательно, то оно отсчитывается от конца строки.
Таким образом, .at(-1)
означает последний символ, а .at(-2)
— предшествующий ему и т. д.
Квадратные скобки всегда возвращают undefined
для отрицательных индексов, например:
let str = `Привет`; предупреждение(ул[-2]); // неопределенный предупреждение(str.at(-2)); // л
Мы также можем перебирать символы, используя for..of
:
for (let char of "Hello") { предупреждение (символ); // H,e,l,l,o (символ становится "H", затем "e", затем "l" и т. д.) }
Строки не могут быть изменены в JavaScript. Изменить персонажа невозможно.
Давайте попробуем показать, что это не работает:
пусть str = 'Привет'; стр[0] = 'ч'; // ошибка предупреждение (ул[0]); // не работает
Обычный обходной путь — создать совершенно новую строку и назначить ее str
вместо старой.
Например:
пусть str = 'Привет'; стр = 'ч' + стр[1]; // заменяем строку оповещение (ул); // привет
В следующих разделах мы увидим больше примеров этого.
Методы toLowerCase() и toUpperCase() изменяют регистр:
alert('Интерфейс'.toUpperCase()); // ИНТЕРФЕЙС Предупреждение('Интерфейс'.toLowerCase()); // интерфейс
Или, если мы хотим, чтобы один символ был в нижнем регистре:
alert( 'Интерфейс'[0].toLowerCase()); // 'я'
Существует несколько способов поиска подстроки внутри строки.
Первый метод — str.indexOf(substr, pos).
Он ищет substr
в str
, начиная с заданной позиции pos
, и возвращает позицию, в которой было найдено совпадение, или -1
если ничего не найдено.
Например:
let str = 'Виджет с идентификатором'; alert(str.indexOf('Виджет')); // 0, потому что «Виджет» находится в начале alert(str.indexOf('виджет')); // -1, не найдено, поиск чувствителен к регистру Предупреждение(str.indexOf("id")); // 1, "id" находится в позиции 1 (..idget с идентификатором)
Необязательный второй параметр позволяет нам начать поиск с заданной позиции.
Например, первое появление "id"
находится в позиции 1
. Чтобы найти следующее вхождение, начнем поиск с позиции 2
:
let str = 'Виджет с идентификатором'; alert( str.indexOf('id', 2) ) // 12
Если нас интересуют все вхождения, мы можем запустить indexOf
в цикле. Каждый новый вызов выполняется с позиции после предыдущего совпадения:
let str = 'Хитрый, как лиса, сильный, как бык'; пусть цель = 'как'; // давайте поищем его пусть пос = 0; в то время как (истина) { пусть FoundPos = str.indexOf(target, pos); если (foundPos == -1) сломать; alert(`Найдено в ${foundPos}`); поз = найденоПос + 1; // продолжаем поиск со следующей позиции }
Тот же алгоритм можно изложить короче:
let str = "Хитрый, как лиса, сильный, как бык"; пусть цель = "как"; пусть пос = -1; while ((pos = str.indexOf(target, pos + 1)) != -1) { предупреждение (поз.); }
str.lastIndexOf(substr, position)
Существует также аналогичный метод str.lastIndexOf(substr,position), который выполняет поиск от конца строки к ее началу.
В нем будут перечислены события в обратном порядке.
Есть небольшое неудобство с indexOf
в тесте if
. Мы не можем поместить это в if
вот так:
let str = "Виджет с идентификатором"; if (str.indexOf("Виджет")) { alert("Мы нашли это"); // не работает! }
alert
в приведенном выше примере не отображается, поскольку str.indexOf("Widget")
возвращает 0
(это означает, что совпадение найдено в начальной позиции). Верно, но if
считает 0
false
.
Итак, нам действительно следует проверить наличие -1
, например:
let str = "Виджет с идентификатором"; if (str.indexOf("Виджет") != -1) { alert("Мы нашли это"); // теперь работает! }
Более современный метод str.includes(substr, pos) возвращает true/false
в зависимости от того, содержит ли str
внутри substr
.
Это правильный выбор, если нам нужно проверить совпадение, но не нужна его позиция:
alert("Виджет с идентификатором".includes("Виджет") ); // истинный alert( "Привет".includes("Пока")); // ЛОЖЬ
Необязательный второй аргумент str.includes
— это позиция, с которой начинается поиск:
alert( "Виджет".includes("id")); // истинный alert( "Виджет".includes("id", 3) ); // false, с позиции 3 нет "id"
Методы str.startsWith и str.endsWith делают именно то, что говорят:
alert( "Виджет".startsWith("Wid")); // правда, «Виджет» начинается с «Wid» alert( "Виджет".endsWith("получить")); // правда, «Виджет» заканчивается на «get»
В JavaScript есть три метода получения подстроки: substring
, substr
и slice
.
str.slice(start [, end])
Возвращает часть строки от start
до end
(но не включая его).
Например:
let str = "stringify"; предупреждение(str.slice(0, 5)); // 'строка', подстрока от 0 до 5 (не включая 5) предупреждение(str.slice(0, 1)); // 's', от 0 до 1, но не включая 1, поэтому только символ 0
Если второго аргумента нет, то slice
продолжается до конца строки:
let str = "stringify"; предупреждение(str.slice(2)); // 'ringify', со 2-й позиции до конца
Также возможны отрицательные значения start/end
. Они означают, что позиция отсчитывается от конца строки:
let str = "stringify"; // начинаем с 4-й позиции справа, заканчиваем на 1-й позиции справа предупреждение( str.slice(-4, -1) ); // 'гиф'
str.substring(start [, end])
Возвращает часть строки между start
и end
(не включая end
).
Это почти то же самое, что и slice
, но позволяет start
быть больше, чем end
(в этом случае просто меняются местами start
и end
значения).
Например:
let str = "stringify"; // это то же самое для подстроки предупреждение(str.substring(2, 6)); // "кольцо" предупреждение(str.substring(6, 2)); // "кольцо" // ...но не для среза: предупреждение(str.slice(2, 6)); // "кольцо" (то же самое) предупреждение(str.slice(6, 2)); // "" (пустая строка)
Отрицательные аргументы (в отличие от среза) не поддерживаются, они обрабатываются как 0
.
str.substr(start [, length])
Возвращает часть строки от start
заданной length
.
В отличие от предыдущих методов, этот позволяет нам указать length
вместо конечной позиции:
let str = "stringify"; предупреждение(str.substr(2, 4)); // 'кольцо', со второй позиции получаем 4 символа
Первый аргумент может быть отрицательным, если считать с конца:
let str = "stringify"; предупреждение(str.substr(-4, 2)); // 'gi', с 4-й позиции получаем 2 символа
Этот метод находится в Приложении B спецификации языка. Это означает, что его должны поддерживать только движки Javascript, размещенные в браузере, и его не рекомендуется использовать. На практике это поддерживается везде.
Давайте повторим эти методы, чтобы избежать путаницы:
метод | выбирает… | негативы |
---|---|---|
slice(start, end) | от start до end (не включая end ) | допускает негативы |
substring(start, end) | между start и end (не включая end ) | отрицательные значения означают 0 |
substr(start, length) | с start получить length символов | допускает отрицательный start |
Какой выбрать?
Все они могут выполнить эту работу. Формально substr
есть небольшой недостаток: он описан не в базовой спецификации JavaScript, а в Приложении B, которое охватывает только браузерные функции, существующие в основном по историческим причинам. Таким образом, небраузерные среды могут не поддерживать его. Но на практике это работает везде.
Из двух других вариантов slice
немного более гибок, он допускает отрицательные аргументы и короче на запись.
Итак, для практического использования достаточно запомнить только slice
.
Как мы знаем из главы «Сравнения», строки сравниваются посимвольно в алфавитном порядке.
Хотя и есть некоторые странности.
Строчная буква всегда больше прописной:
Предупреждение('a' > 'Z'); // истинный
Буквы с диакритическими знаками «не в порядке»:
alert('Остеррайх' > 'Зеландия'); // истинный
Это может привести к странным результатам, если мы отсортируем эти названия стран. Обычно люди ожидают, что Zealand
пойдет в списке после Österreich
.
Чтобы понять, что происходит, нам следует знать, что строки в Javascript кодируются с использованием UTF-16. То есть: каждому символу соответствует цифровой код.
Существуют специальные методы, позволяющие получить символ по коду и обратно:
str.codePointAt(pos)
Возвращает десятичное число, представляющее код символа в позиции pos
:
// разные регистровые буквы имеют разные коды Предупреждение( "Z".codePointAt(0)); // 90 Предупреждение( "z".codePointAt(0)); // 122 alert( "z".codePointAt(0).toString(16) ); // 7a (если нам нужно шестнадцатеричное значение)
String.fromCodePoint(code)
Создает символ по его числовому code
предупреждение( String.fromCodePoint(90) ); // Я предупреждение(String.fromCodePoint(0x5a)); // Z (мы также можем использовать шестнадцатеричное значение в качестве аргумента)
Теперь посмотрим символы с кодами 65..220
(латинский алфавит и еще немного), составив из них строку:
пусть строка = ''; for (пусть я = 65; я <= 220; я++) { стр += String.fromCodePoint(i); } предупреждение(ул); // Выход: // ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~ € ‚ƒ„ // ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜ
Видеть? Сначала идут заглавные символы, затем несколько специальных, затем строчные и Ö
ближе к концу вывода.
Теперь становится очевидным, почему a > Z
Символы сравниваются по их числовому коду. Больший код означает, что символ больше. a
для (97) больше, чем код для Z
(90).
Все строчные буквы идут после прописных, потому что их коды больше.
Некоторые буквы, такие как Ö
стоят отдельно от основного алфавита. Здесь его код больше, чем что-либо от a
до z
.
«Правильный» алгоритм сравнения строк сложнее, чем может показаться, поскольку алфавиты в разных языках разные.
Итак, браузеру необходимо знать язык для сравнения.
К счастью, современные браузеры поддерживают стандарт интернационализации ECMA-402.
Он предоставляет специальный метод для сравнения строк на разных языках, следуя их правилам.
Вызов str.localeCompare(str2) возвращает целое число, указывающее, является ли str
меньше, равной или большей, чем str2
в соответствии с правилами языка:
Возвращает отрицательное число, если str
меньше str2
.
Возвращает положительное число, если str
больше str2
.
Возвращает 0
если они эквивалентны.
Например:
alert('Österreich'.localeCompare('Зеландия')); // -1
На самом деле этот метод имеет два дополнительных аргумента, указанных в документации, что позволяет ему указывать язык (по умолчанию берется из среды, порядок букв зависит от языка) и устанавливать дополнительные правила, такие как чувствительность к регистру или следует использовать "a"
и "á"
относиться как к одному и т. д.
Есть 3 типа котировок. Обратные кавычки позволяют строке занимать несколько строк и вставлять выражения ${…}
.
Мы можем использовать специальные символы, такие как разрыв строки n
.
Чтобы получить символ, используйте: []
или метод at
.
Чтобы получить подстроку, используйте: slice
или substring
.
Чтобы ввести строку в нижний/верхний регистр, используйте: toLowerCase/toUpperCase
.
Чтобы найти подстроку, используйте indexOf
или includes/startsWith/endsWith
для простых проверок.
Для сравнения строк по языку используйте: localeCompare
, в противном случае они сравниваются по кодам символов.
Есть еще несколько полезных методов в строках:
str.trim()
– удаляет («обрезает») пробелы в начале и конце строки.
str.repeat(n)
– повторяет строку n
раз.
…и многое другое можно найти в руководстве.
Строки также имеют методы для поиска/замены с помощью регулярных выражений. Но это большая тема, поэтому она объясняется в отдельном разделе руководства «Регулярные выражения».
Кроме того, на данный момент важно знать, что строки основаны на кодировке Unicode, и, следовательно, возникают проблемы со сравнением. Дополнительную информацию о Unicode можно найти в главе Unicode, Внутреннее устройство строк.
важность: 5
Напишите функцию ucFirst(str)
, которая возвращает строку str
с первым символом в верхнем регистре, например:
ucFirst("Джон") == "Джон";
Откройте песочницу с тестами.
Мы не можем «заменить» первый символ, поскольку строки в JavaScript неизменяемы.
Но мы можем создать новую строку на основе существующей, с первым символом в верхнем регистре:
let newStr = str[0].toUpperCase() + str.slice(1);
Однако есть небольшая проблема. Если str
пуста, то str[0]
undefined
, а поскольку undefined
нет метода toUpperCase()
, мы получим ошибку.
Самый простой выход — добавить тест для пустой строки, например:
функция ucFirst(str) { if (!str) вернуть str; return str[0].toUpperCase() + str.slice(1); } Предупреждение(ucFirst("Джон")); // Джон
Откройте решение с тестами в песочнице.
важность: 5
Напишите функцию checkSpam(str)
, которая возвращает true
если str
содержит «виагра» или «XXX», в противном случае false
.
Функция должна быть нечувствительна к регистру:
checkSpam('купить ViAgRA сейчас') == true checkSpam('бесплатно xxxxx') == true checkSpam("невинный кролик") == false
Откройте песочницу с тестами.
Чтобы сделать поиск нечувствительным к регистру, давайте переведем строку в нижний регистр, а затем выполните поиск:
функция checkSpam(str) { let lowStr = str.toLowerCase(); return lowStr.includes('виагра') || lowStr.includes('xxx'); } alert( checkSpam('купить ВиАгРА сейчас') ); оповещение(checkSpam('бесплатно xxxxx')); alert(checkSpam("невинный кролик"));
Откройте решение с тестами в песочнице.
важность: 5
Создайте функцию truncate(str, maxlength)
, которая проверяет длину str
и, если она превышает maxlength
, заменяет конец str
символом многоточия "…"
, чтобы сделать ее длину равной maxlength
.
Результатом функции должна быть усеченная (при необходимости) строка.
Например:
truncate("Что я хотел бы сказать по этой теме:", 20) == "Что я хотел бы сказать…" truncate("Всем привет!", 20) == "Всем привет!"
Откройте песочницу с тестами.
Максимальная длина должна быть maxlength
, поэтому нам нужно обрезать ее немного короче, чтобы освободить место для многоточия.
Обратите внимание, что на самом деле для многоточия используется один символ Юникода. Это не три точки.
функция truncate(str, maxlength) { return (str.length > maxlength)? str.slice(0, maxlength - 1) + '…' : str; }
Откройте решение с тестами в песочнице.
важность: 4
У нас есть стоимость в виде "$120"
. То есть: сначала идет знак доллара, а потом цифра.
Создайте функцию extractCurrencyValue(str)
, которая будет извлекать числовое значение из такой строки и возвращать его.
Пример:
alert(extractCurrencyValue('$120') === 120 ); // истинный
Откройте песочницу с тестами.
функция extractCurrencyValue(str) { вернуть +str.slice(1); }
Откройте решение с тестами в песочнице.