В JavaScript любые текстовые данные являются строками. Даже один символ - строка.
Все строки, вне зависимости от кодировки, хранятся в формате Юникод (Unicode).
Создание строк
Строки создаются при помощи двойных или одинарных кавычек:
var text = "моя строка"; var anotherText = 'еще строка'; var str = "012345";
В JavaScript нет разницы между двойными и одинарными кавычками.
Специальные символы
Строки могут содержать специальные символы. Самый часто используемый из таких символов - это перевод строки.
Он обозначается как \n, например:
alert('Привет\nМир'); // выведет "Мир" на новой строке
Есть и более редкие символы, вот их список:
| Символ | Описание |
|---|---|
| \b | Backspace |
| \f | Form feed |
| \n | New line |
| \r | Carriage return |
| \t | Tab |
| \uNNNN | Символ в кодировке Юникод с шестнадцатиричным кодом NNNN. Например, \u00A9 - юникодное представление символа копирайт ©
|
Экранирование специальных символов
Если строка в одинарных кавычках, то внутренние одинарные кавычки внутри должны быть экранированы, то есть снабжены обратным слешем \', вот так:
var str = '*!*I\'m*/!* a JavaScript programmer';
В двойных кавычках — экранируются внутренние двойные:
var str = "I'm a JavaScript \"programmer\" "; alert(str);
Экранирование служит исключительно для правильного восприятия строки JavaScript. В памяти строка будет содержать сам символ без '\'. Вы можете увидеть это, запустив пример выше.
Сам символ обратного слэша '\' является служебным, поэтому всегда экранируется, т.е пишется как \\:
var str = ' символ \\ '; alert(str); // символ \
Заэкранировать можно любой символ. Если он не специальный, то ничего не произойдёт:
alert( "\a" ); // a // идентично alert( "a" );
Методы и свойства
Здесь мы рассмотрим методы и свойства строк, с некоторыми из которых мы знакомились ранее, в главе Методы и свойства.
Длина length
Одно из самых частых действий со строкой — это получение ее длины:
var str = "My\n"; // 3 символа. Третий - перевод строки alert(str.length); // 3
Доступ к символам
Чтобы получить символ, используйте вызов charAt(позиция). Первый символ имеет позицию 0:
var str = "jQuery"; alert( str.charAt(0) ); // "j"
В JavaScript нет отдельного типа «символ», так что charAt возвращает строку, состоящую из выбранного символа.
В современных браузерах (кроме IE<8) для доступа к символу можно также использовать квадратные скобки:
var str = "Я - современный браузер!"; alert(str[0]); // "Я", IE8+
Разница между этим способом и charAt заключается в том, что если символа нет — charAt выдает пустую строку, а скобки — undefined:
alert( "".charAt(0) ); // пустая строка alert( ""[0] ); // undefined, IE8+
Обратите внимание, str.length — это свойство строки, а str.charAt(pos) — метод, т.е. функция.
Обращение к методу всегда идет со скобками, а к свойству — без скобок.
Изменения строк
Строки в JavaScript нельзя изменять. Можно прочитать символ, но нельзя заменить его. Как только строка создана — она такая навсегда.
Чтобы это обойти, создаётся новая строка и присваивается в переменную вместо старой:
var str = "строка"; str = str.charAt(3) + str.charAt(4) + str.charAt(5); alert(str); // ока
Смена регистра
Методы toLowerCase() и toUpperCase() меняют регистр строки на нижний/верхний:
alert( "Интерфейс".toUpperCase() ); // ИНТЕРФЕЙС
Пример ниже получает первый символ и приводит его к нижнему регистру:
alert( "Интерфейс".charAt(0).toLowerCase() ); // 'и'
Напишите функцию ucFirst(str), которая возвращает строку str с заглавным первым символом, например:
ucFirst("вася") == "Вася"
P.S. В JavaScript нет встроенного метода для этого. Создайте функцию, используя toUpperCase() и charAt().
Мы не можем просто заменить первый символ, т.к. строки в JavaScript неизменяемы.
Единственный способ - пересоздать строку на основе существующей, но с заглавным первым символом:
function ucFirst(str) {
var newStr = str.charAt(0).toUpperCase();
for(var i=1; i<str.length; i++) {
newStr += str.charAt(i);
}
return newStr;
}
alert( ucFirst("вася") );
P.S. Существуют и другие решения, использующие метод substr, а также регулярные выражения.
Поиск подстроки
Для поиска подстроки есть метод indexOf(подстрока[, начальная_позиция]).
Он возвращает позицию, на которой находится подстрока или -1, если ничего не найдено. Например:
var str = "Widget with id";
alert( str.indexOf("Widget") ); // 0, т.к. "Widget" найден прямо в начале str
alert( str.indexOf("id") ); // 1, т.к. "id" найден, начиная с позиции 1
alert( str.indexOf("Lalala") ); // -1, подстрока не найдена
Необязательный второй аргумент позволяет искать, начиная с указанной позиции. Например, первый раз "id" появляется на позиции 1. Чтобы найти его следующее появление - запустим поиск с позиции 2:
var str = "Widget with id";
alert( str.indexOf("id", 2) ) // 12, поиск начат с позиции 2
Также существует аналогичный метод lastIndexOf, который ищет не с начала, а с конца строки.
Для красивого вызова indexOf применяется побитовый оператор НЕ '~'.
Дело в том, что вызов ~n эквивалентен выражению -(n+1), например:
alert( ~2 ); // -(2+1) = -3 alert( ~1 ); // -(1+1) = -2 alert( ~0 ); // -(0+1) = -1 *!* alert( ~-1 ); // -(-1+1) = 0 */!*
Как видно, ~n - ноль только в случае, когда n == -1.
То есть, проверка if ( ~str.indexOf(...) ) означает, что результат indexOf отличен от `-1, т.е. совпадение есть.
Вот так:
var str = "Widget";
if( ~str.indexOf("get") ) {
alert('совпадение есть!');
}
Вообще, использовать возможности языка неочевидным образом не рекомендуется, поскольку ухудшает читаемость кода.
Однако, в данном случае, все в порядке. Просто запомните: '~' читается как «не минус один», а "if ~str.indexOf" читается как "если найдено".
Напишите функцию checkSpam(str), которая возвращает true, если строка str содержит ‘viagra’ or ‘XXX’.
Функция должна быть нечувствительна к регистру:
checkSpam('buy ViAgRA now') == true
checkSpam('free xxxxx') == true
checkSpam("innocent rabbit") == false
Метод indexOf ищет совпадение с учетом регистра. То есть, в строке 'xXx' он не найдет 'XXX'.
Для проверки приведем к нижнему регистру и строку str и то, что будем искать:
function checkSpam(str) {
str = str.toLowerCase();
return str.indexOf('viagra') >= 0 || str.indexOf('xxx') >= 0;
}
Полное решение: tutorial/intro/checkSpam.html.
Взятие подстроки: substr, substring, slice.
В JavaScript существуют целых 3 (!) метода для взятия подстроки, с небольшими отличиями между ними.
substring(start [, end])-
Метод
substring(start, end)возвращает подстроку с позицииstartдо, но не включаяend.var str = "*!*s*/!*tringify"; alert(str.substring(0,1)); // "s", символы с позиции 0 по 1 не включая 1.
Если аргумент
endотсутствует, то идет до конца строки:var str = "st*!*ringify*/!*"; alert(str.substring(2)); // ringify, символы с позиции 2 до конца
substr(start [, length])- Первый аргумент имеет такой же смысл, как и в
substring, а второй содержит не конечную позицию, а количество символов.var str = "st*!*ring*/!*ify"; str = str.substr(2,4); // ring, со 2й позиции 4 символа alert(str)
Если второго аргумента нет - подразумевается «до конца строки».
slice(start [, end])- Возвращает часть строки от позиции
startдо, но не включая, позицииend. Смысл параметров - такой же как вsubstring.
Различие между substring и slice - в том, как они работают с отрицательными и выходящими за границу строки параметрами:
substring(start, end)- Отрицательные аргументы интерпретируются как равные нулю. Слишком большие значения усекаются до длины строки:
alert( "testme".substring(-2) ); // "testme", -2 становится 0
Кроме того, если
start > end, то аргументы меняются местами, т.е. возвращается участок строки междуstartиend:alert( "testme".substring(4, -1) ); // "test" // -1 становится 0 -> получили substring(4, 0) // 4 > 0, так что аргументы меняются местами -> substring(0, 4) = "test"
slice- Отрицательные значения отсчитываются от конца строки:
alert( "testme".slice(-2) ); // "me", от 2 позиции с конца
alert( "testme".slice(1, -1) ); // "estm", от 1 позиции до первой с конца.
Это гораздо более удобно, чем странная логика
substring.
Отрицательное значение start также поддерживается в substr во всех браузерах, кроме IE.
Выводы.
Самый удобный метод - это slice(start, end).
В качестве альтернативы можно использовать substr(start, length). При этом start должен быть неотрицательным для IE.
Создайте функцию truncate(str, maxlength), которая проверяет длину строки str, и если она превосходит maxlength — заменяет конец str на '…', так чтобы ее длина стала равна maxlength.
Результатом функции должна быть (при необходимости) усечённая строка.
Например:
truncate("Вот, что мне хотелось бы сказать на эту тему:", 20)) = "Вот, что мне хотело…"
truncate("Всем привет!", 20)) = "Всем привет!"
Эта функция имеет применение в жизни. Она используется, чтобы усекать слишком длинные темы сообщений.
Так как окончательная длина строки должна быть maxlength, то нужно её обрезать немного короче, чтобы дать место для троеточия.
function truncate(str, maxlength) {
if (str.length > maxlength) {
return str.slice(0, maxlength - 3) + '...';
// итоговая длина равна maxlength
}
return str;
}
alert(truncate("Вот, что мне хотелось бы сказать на эту тему:", 20))
alert(truncate("Всем привет!", 20))
Ещё лучшим вариантом будет использование вместо трёх точек специального символа «троеточие»: … (…), тогда можно отрезать один символ.
function truncate(str, maxlength) {
if (str.length > maxlength) {
return str.slice(0, maxlength - 1) + '…';
}
return str;
}
alert(truncate("Вот, что мне хотелось бы сказать на эту тему:", 20))
alert(truncate("Всем привет!", 20))
Можно было бы написать этот код короче:
function truncate(str, maxlength) {
return (str.length > maxlength) ?
str.slice(0, maxlength - 1) + '…' : str;
}
alert(truncate("Вот, что мне хотелось бы сказать на эту тему:", 20))
alert(truncate("Всем привет!", 20))
Кодировка Юникод
Если вы знакомы со сравнением строк в других языках, то позвольте предложить одну маленькую загадку. Даже не одну, а целых две.
Как мы знаем, символы сравниваются в алфавитном порядке 'А' < 'Б' < 'В' < ... < 'Я'.
Но есть несколько странностей..
- Почему буква
'а'маленькая больше буквы'Я'большой?
alert( 'а' > 'Я' ); // true
-
Буква
'ё'находится в алфавите междуеиж:абвгдеёжз... Но почему тогда'ё'больше'я'?
alert( 'ё' > 'я' ); // true
Чтобы разобраться с этим, обратимся к внутреннему представлению строк в JavaScript.
Все строки имеют внутреннюю кодировку Юникод.
Вообще, в мире много разных кодировок, и страница может быть в любой из них. Но внутри JavaScript-интерпретатора все строки находятся в кодировке юникод.
Есть метод для получения символа по его цифровому коду:
- String.fromCharCode(code)
- Возвращает символ по коду
code:
alert( String.fromCharCode(1072) ); // 'а'
… И метод для получения цифрового кода:
- str.charCodeAt(pos)
- Возвращает код символа на позиции
pos. Отсчет позиции начинается с нуля.
alert( "абрикос".charCodeAt(0) ); // 1072, код 'а'
Теперь вернемся к примерам выше. Почему сравнения 'ё' > 'я' и 'а' > 'Я' дают такой странный результат?
Дело в том, что символы сравниваются не по алфавиту, а по коду. У кого код больше — тот и больше. В юникоде есть много разных символов. Славянским языкам соответствуют коды примерно от 1024 до 1119.
Так их можно получить:
var s = '';
for (var i=1024; i<=1119; i++) {
s += String.fromCharCode(i);
}
Результат:
?ЁЂЃЄЅІЇЈЉЊЋЌ?ЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя?ёђѓєѕіїјљњћќ?ўџ
Промежуток взят «с запасом», так что можно увидеть некириллические символы в начале и в конце.
Мы можем увидеть из этого отрезка кодировки две вещи:
- Строчные буквы идут после заглавных, поэтому они всегда больше.
В частности,'а'(код 1072) > 'Я'(код 1071).
Кстати, то же самое и в английском алфавите, там'a' > 'Z'. - Ряд букв, например
ё, находятся вне основного алфавита.
Это объясняет, почему'ё'(код 1105) > 'я'(код 1103).
Кстати, если мы знаем код символа в кодировке юникод, то можем использовать его и в HTML.
Чтобы вставить символ с данным кодом в HTML, нужно написать сначала &#, затем код, и завершить точкой с запятой ';'. Например, буква 'а'в HTML: а.
Если код хотят дать в 16-ричной системе счисления, то начинают с &#x.
Например, символ ножниц: ✂(✂), дроби: ½ (½) ¾ (¾). В юникоде есть и много других забавных символов.
Сравнение строк
Строки сравниваются лексикографически, в порядке «телефонного справочника».
Сравнение строк s1 и s2 обрабатывается по следующему алгоритму:
- Сравниваются первые символы:
a = s1.charAt(0)иb = s2.charAt(0). Если они одинаковы, то следующий шаг, иначе, в зависимости от результата их сравнения, возвратитьtrueилиfalse - Сравниваются вторые символы, затем третьи и так далее… Если в одной строке закончились символы, то она меньше. Если в обоих закончились - они равны.
Спецификация языка определяет этот алгоритм более детально, но смысл в точности соответствует порядку, по которому имена заносятся в телефонный справочник.
"Z" > "A" // true "Вася" > "Ваня" // true, т.к. с > н "aa" > "a" // true, т.к. начало совпадает, но в 1й строке больше символов
Обратим внимание на результат сравнения чисел в строковой форме. Он может быть неверным:
alert("2" > "14"); // true, т.к. это строки и "2" > "1"
Чтобы получать верный результат, хотя бы один из аргументов должен не быть строкой. Тогда и другой будет преобразован к числу:
alert(2 > "14"); // false
Итого
- Строки в JavaScript имеют внутреннюю кодировку Юникод. При написании строки можно использовать спец. символы и вставлять юникодные символы по коду.
- Мы познакомились со свойством
lengthи методамиcharAt,toLowerCase/toUpperCase,substring/substr/slice(предпочтителенslice) - Строки сравниваются побуквенно. Поэтому если число получено в виде строки, то такие числа могут сравниваться некорректно, нужно преобразовать его к типу number.
Больше информации о методах для строк можно получить в справочнике: http://javascript.ru/String.
Комментарии
- Приветствуются комментарии, содержащие дополнения и вопросы по статье, и ответы на них.
- Если ваш комментарий касается задачи -- откройте её в отдельном окне и напишите там.
- Комментарии без смысла, с рекламой или не о статье вообще - удаляются.