Лекция
Привет, сегодня поговорим про строки в javascript, обещаю рассказать все что знаю. Для того чтобы лучше понимать что такое строки в javascript , настоятельно рекомендую прочитать все из категории Выполнение скриптов на стороне клиента JavaScript, jqvery, JS фреймворки (Frontend).
length
substr
, substring
, slice
.В JavaScript любые текстовые данные являются строками. Не существует отдельного типа «символ», который есть в ряде других языков.
Внутренним форматом строк, вне зависимости от кодировки страницы, является Юникод (Unicode).
Строки создаются при помощи двойных или одинарных кавычек:
1 |
var text = "моя строка" ; |
2 |
3 |
var anotherText = 'еще строка' ; |
4 |
5 |
var str = "012345" ; |
В JavaScript нет разницы между двойными и одинарными кавычками.
Строки могут содержать специальные символы. Самый часто используемый из таких символов — этоперевод строки.
Он обозначается как \n
, например:
1 |
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' ; |
В двойных кавычках — экранируются внутренние двойные:
1 |
var str = "I'm a JavaScript \"programmer\" " ; |
2 |
alert(str); |
Экранирование служит исключительно для правильного восприятия строки JavaScript. В памяти строка будет содержать сам символ без '\'
. Вы можете увидеть это, запустив пример выше.
Сам символ обратного слэша '\'
является служебным, поэтому всегда экранируется, т.е пишется как\\
:
1 |
var str = ' символ \\ ' ; |
2 |
3 |
alert(str); // символ \ |
Заэкранировать можно любой символ. Если он не специальный, то ничего не произойдет:
1 |
alert( "\a" ); // a |
2 |
// идентично alert( "a" ); |
Здесь мы рассмотрим методы и свойства строк, с некоторыми из которых мы знакомились ранее, в главе Методы и свойства.
length
Одно из самых частых действий со строкой — это получение ее длины:
1 |
var str = "My\n" ; // 3 символа. Третий - перевод строки |
2 |
3 |
alert(str.length); // 3 |
Чтобы получить символ, используйте вызов charAt(позиция)
. Первый символ имеет позицию 0
:
1 |
var str = "jQuery" ; |
2 |
alert( str.charAt(0) ); // "j" |
В JavaScript нет отдельного типа «символ», так что charAt
возвращает строку, состоящую из выбранного символа.
В современных браузерах (не IE7-) для доступа к символу можно также использовать квадратные скобки:
1 |
var str = "Я - современный браузер!" ; |
2 |
alert(str[0]); // "Я", IE8+ |
Разница между этим способом и charAt
заключается в том, что если символа нет —charAt
выдает пустую строку, а скобки — undefined
:
1 |
alert( "" .charAt(0) ); // пустая строка |
2 |
alert( "" [0] ); // undefined, IE8+ |
Обратите внимание, str.length
— это свойство строки, а str.charAt(pos)
—метод, т.е. функция.
Обращение к методу всегда идет со скобками, а к свойству — без скобок.
строки в javascript нельзя изменять. Можно прочитать символ, но нельзя заменить его. Как только строка создана — она такая навсегда.
Чтобы это обойти, создается новая строка и присваивается в переменную вместо старой:
1 |
var str = "строка" ; |
2 |
3 |
str = str.charAt(3) + str.charAt(4) + str.charAt(5); |
4 |
5 |
alert(str); // ока |
Методы toLowerCase()
и toUpperCase()
меняют регистр строки на нижний/верхний:
1 |
alert( "Интерфейс" .toUpperCase() ); // ИНТЕРФЕЙС |
Пример ниже получает первый символ и приводит его к нижнему регистру:
alert( "Интерфейс" .charAt(0).toLowerCase() ); // 'и' |
Для поиска подстроки есть метод indexOf(подстрока[, начальная_позиция]).
Он возвращает позицию, на которой находится подстрока
или -1
, если ничего не найдено. Например:
1 |
var str = "Widget with id" ; |
2 |
3 |
alert( str.indexOf( "Widget" ) ); // 0, т.к. "Widget" найден прямо в начале str |
4 |
alert( str.indexOf( "id" ) ); // 1, т.к. "id" найден, начиная с позиции 1 |
5 |
alert( str.indexOf( "Lalala" ) ); // -1, подстрока не найдена |
Необязательный второй аргумент позволяет искать, начиная с указанной позиции. Об этом говорит сайт https://intellect.icu . Например, первый раз "id"
появляется на позиции 1
. Чтобы найти его следующее появление — запустим поиск с позиции2
:
1 |
var str = "Widget with id" ; |
2 |
3 |
alert( str.indexOf( "id" , 2) ) // 12, поиск начат с позиции 2 |
Также существует аналогичный метод lastIndexOf, который ищет не с начала, а с конца строки.
Для красивого вызова indexOf
применяется побитовый оператор НЕ '~'
.
Дело в том, что вызов ~n
эквивалентен выражению -(n+1)
, например:
1 |
alert( ~2 ); // -(2+1) = -3 |
2 |
alert( ~1 ); // -(1+1) = -2 |
3 |
alert( ~0 ); // -(0+1) = -1 |
4 |
alert( ~-1 ); // -(-1+1) = 0 |
Как видно, ~n
— ноль только в случае, когда n == -1
.
То есть, проверка if ( ~str.indexOf(...) )
означает, что результат indexOf
отличен от `-1, т.е. совпадение есть.
Вот так:
1 |
var str = "Widget" ; |
2 |
3 |
if ( ~str.indexOf( "get" ) ) { |
4 |
alert( 'совпадение есть!' ); |
5 |
} |
Вообще, использовать возможности языка неочевидным образом не рекомендуется, поскольку ухудшает читаемость кода.
Однако, в данном случае, все в порядке. Просто запомните: '~'
читается как «не минус один», а "if ~str.indexOf"
читается как "если найдено"
.
Чтобы найти все вхождения подстроки, нужно запустить indexOf
в цикле. Как только получаем очередную позицию — начинаем следующий поиск со следующей.
Пример такого цикла:
01 |
var str = "Ослик Иа-Иа посмотрел на виадук" ; // ищем в этой строке |
02 |
var target = "Иа" ; // цель поиска |
03 |
04 |
var pos = 0; |
05 |
while ( true ) { |
06 |
var foundPos = str.indexOf(target, pos); |
07 |
if (foundPos == -1) break ; |
08 |
09 |
alert(foundPos); // нашли на этой позиции |
10 |
pos = foundPos + 1; // продолжить поиск со следующей |
11 |
} |
Такой цикл начинает поиск с позиции 0
, затем найдя подстроку на позиции foundPos
, следующий поиск продолжит с позиции pos = foundPos+1
, и так далее, пока что-то находит.
Впрочем, тот же алгоритм можно записать и короче:
1 |
var str = "Ослик Иа-Иа посмотрел на виадук" ; // ищем в этой строке |
2 |
var target = "Иа" ; // цель поиска |
3 |
4 |
var pos = -1; |
5 |
while ( (pos = str.indexOf(target, pos+1)) != -1) { |
6 |
alert(pos); |
7 |
} |
substr
, substring
, slice
.В JavaScript существуют целых 3 (!) метода для взятия подстроки, с небольшими отличиями между ними.
substring(start [, end])
substring(start, end)
возвращает подстроку с позиции start
до, но не включая end
.
1 |
var str = "stringify" ; |
2 |
alert(str.substring(0,1)); // "s", символы с позиции 0 по 1 не включая 1. |
Если аргумент end
отсутствует, то идет до конца строки:
1 |
var str = "stringify" ; |
2 |
alert(str.substring(2)); // ringify, символы с позиции 2 до конца |
substr(start [, length])
substring
, а второй содержит не конечную позицию, а количество символов.
1 |
var str = "stringify" ; |
2 |
str = str.substr(2,4); // ring, со 2й позиции 4 символа |
3 |
alert(str) |
Если второго аргумента нет — подразумевается «до конца строки».
slice(start [, end])
start
до, но не включая, позиции end
. Смысл параметров — такой же как в substring
.Различие между substring
и slice
— в том, как они работают с отрицательными и выходящими за границу строки аргументами:
substring(start, end)
1 |
alert( "testme" .substring(-2) ); // "testme", -2 становится 0 |
Кроме того, если start > end
, то аргументы меняются местами, т.е. возвращается участок строки между start
и end
:
1 |
alert( "testme" .substring(4, -1) ); // "test" |
2 |
// -1 становится 0 -> получили substring(4, 0) |
3 |
// 4 > 0, так что аргументы меняются местами -> substring(0, 4) = "test" |
slice
1 |
alert( "testme" .slice(-2) ); // "me", от 2 позиции с конца |
1 |
alert( "testme" .slice(1, -1) ); // "estm", от 1 позиции до первой с конца. |
Это гораздо более удобно, чем странная логика substring
.
Отрицательное значение первого параметра поддерживается в substr
во всех браузерах, кроме IE8-.
Выводы.
Самый удобный метод — это slice(start, end)
.
В качестве альтернативы можно использовать substr(start, length)
, помня о том, что IE8- не поддерживает отрицательный start
.
Если вы знакомы со сравнением строк в других языках, то позвольте предложить одну маленькую загадку. Даже не одну, а целых две.
Как мы знаем, символы сравниваются в алфавитном порядке 'А' < 'Б' < 'В' < ... < 'Я'
.
Но есть несколько странностей..
'а'
маленькая больше буквы 'Я'
большой?
1 |
alert( 'а' > 'Я' ); // true |
'е'
находится в алфавите между е
и ж
: абвгдеежз..
. Но почему тогда 'е'
больше 'я'
?
1 |
alert( 'е' > 'я' ); // true |
Чтобы разобраться с этим, обратимся к внутреннему представлению строк в JavaScript.
Все строки имеют внутреннюю кодировку Юникод.
Неважно, на каком языке написана страница, находится ли она в windows-1251 или utf-8. Внутри JavaScript-интерпретатора все строки приводятся к единому «юникодному» виду. Каждому символу соответствует свой код.
Есть метод для получения символа по его коду:
code
:
1 |
alert( String.fromCharCode(1072) ); // 'а' |
… И метод для получения цифрового кода из символа:
pos
. Отсчет позиции начинается с нуля.
1 |
alert( "абрикос" .charCodeAt(0) ); // 1072, код 'а' |
Теперь вернемся к примерам выше. Почему сравнения 'е' > 'я'
и 'а' > 'Я'
дают такой странный результат?
Дело в том, что символы сравниваются не по алфавиту, а по коду. У кого код больше — тот и больше. В юникоде есть много разных символов. Кириллическим буквам соответствует только небольшая часть из них, подробнее — Кириллица в Юникоде.
Выведем отрезок символов юникода с кодами от 1034
до 1113
:
1 |
var str = '' ; |
2 |
for ( var i=1034; i<=1113; i++) { |
3 |
str += String.fromCharCode(i); |
4 |
} |
5 |
alert(str); |
ЊЋЌЍЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяѐеђѓєѕіїјљ
Мы можем увидеть из этого отрезка две важных вещи:
'а'(код 1072) > 'Я'(код 1071)
.'a' > 'Z'
.е
, находятся вне основного алфавита.е
имеет код, больший чем я
, поэтому'е'(код 1105) > 'я'(код 1103)
.Ё
располагается в Unicode до А
, поэтому 'Ё'
(код 1025) < 'А'
(код 1040). Удивительно: есть буква меньше чем А
Кстати, если мы знаем код символа в кодировке юникод, то можем добавить его в HTML, используя «числовую ссылку» (numeric character reference).
Для этого нужно написать сначала &#
, затем код, и завершить точкой с запятой ';'
. Например, символ 'а'
в виде числовой ссылки: а
.
Если код хотят дать в 16-ричной системе счисления, то начинают с &#x
.
В юникоде есть много забавных и полезных символов, например, символ ножниц: ✂ (✂
), дроби: ½ (½
) ¾ (¾
) и другие. Их можно удобно использовать вместо картинок в дизайне.
Строки сравниваются лексикографически, в порядке «телефонного справочника».
Сравнение строк s1
и s2
обрабатывается по следующему алгоритму:
a = s1.charAt(0)
и b = s2.charAt(0)
. Если они одинаковы, то следующий шаг, иначе, в зависимости от результата их сравнения, возвратить true
или false
Спецификация языка определяет этот алгоритм более детально, но смысл в точности соответствует порядку, по которому имена заносятся в телефонный справочник.
"Z" > "A" // true |
"Вася" > "Ваня" // true, т.к. с > н |
"aa" > "a" // true, т.к. начало совпадает, но в 1й строке больше символов |
Бывает, что числа приходят в скрипт в виде строк, например как результат prompt
. В этом случае результат их сравнения будет неверным:
1 |
alert( "2" > "14" ); // true, так как это строки, и для первых символов верно "2" > "1" |
Если хотя бы один аргумент — не строка, то другой будет преобразован к числу:
1 |
alert(2 > "14" ); // false |
\n
и вставлять юникодные символы по коду.length
и методами charAt
, toLowerCase/toUpperCase
,substring/substr/slice
(предпочтителен slice
)е
вообще вне основного алфавита.a = 'my string' |
b = new String(object) // синтаксис устарел и не используется |
c = String(object) |
string - Необязательный. Любая группа знаков Юникода.
Объекты String
, как правило, создаются неявно с помощью строковых литералов.
// кавычки любые - без разницы |
var str = "string literal" |
В строковых литералах можно использовать escape-последовательности для представления особых знаков, которые нельзя напрямую использовать в строках, например символа перевода строки или знаков Юникода. При компиляции сценария каждая escape-последовательность в строковом литерале преобразуется в знаки, которые она представляет.
Можно указать юникодный символ явным образом, через его код.
var str = "\u1234" |
Объекты String
, заданные через кавычки (и называемые "примитивными" строками), немного отличаются от объектов String
, созданных с помощью оператора new. Так, например, типом (typeof) данных объекта, созданного при помощи new
, является'object'
, а не 'string'
. И такому объекту можно напрямую назначать дополнительные свойства и методы. В остальном - интерпретатор автоматически превращает примитивные строки в объекты.
"12345" .length // 5 |
Доступ к символам осуществляется при помощи метода String#charAt
return 'cat' .charAt(1); // возвратит "a" |
Также существует отсутствующий в стандарте ECMA-262 способ - обращение к строке как к массиву:
var str = 'cat' |
return str[1] // "a" |
В отличие от языков C/PHP/и т.п., однажды созданную строку нельзя изменить: символы можно только считывать, но не менять.
Для изменения строковой переменной применяется присваивание измененной строки:
str = "строка" |
str = str.charAt(4) + str.charAt(5) + str.charAt(6) // "ока" |
Для сравнения строк используются обычные операторы < >.
Комментарии
Оставить комментарий
Выполнение скриптов на стороне клиента JavaScript, jqvery, JS фреймворки (Frontend)
Термины: Выполнение скриптов на стороне клиента JavaScript, jqvery, JS фреймворки (Frontend)