|
|
escape-последовательностей символов JavaScript · Матиас Байненс
Недавно написав о ссылках на символы в HTML и escape-последовательностях в CSS, я подумал, что было бы интересно изучить и escape-последовательности символов JavaScript.
Коды символов, кодовые точки и кодовые единицы
Кодовая точка (также известная как «код символа» ) представляет собой числовое представление определенного символа Unicode.
Например, код символа авторского права ©
— это 169
, что можно записать как 0xA9
в шестнадцатеричном формате.
В JavaScript String#charCodeAt()
можно использовать для получения числовой кодовой точки Unicode любого символа до U+FFFF (т. е. символа с кодовой точкой 0xFFFF
, что равно 65535
в десятичном виде).
Поскольку внутри JavaScript используется кодировка UCS-2, более высокие кодовые точки представлены парой (с более низким значением) «суррогатных» псевдосимволов, которые используются для составления реального символа. Чтобы получить фактический код символов с более высокими кодовыми точками в JavaScript, вам придется проделать дополнительную работу. По сути, JavaScript использует кодовые единицы, а не кодовые точки.
Теперь, когда это не так, давайте взглянем на различные типы управляющих последовательностей символов в строках JavaScript.
Существуют некоторые зарезервированные последовательности перехода из одного символа для использования в строках:
-
\b
: Backspace (U+0008 BACKSPACE) -
\f
: подача страницы (U+000C ПОДАЧА ФОРМЫ) -
\n
: перевод строки (U+000A LINE FEED) -
\r
: возврат каретки (U+000D ВОЗВРАТ КАРЕТКИ) -
\t
: горизонтальная вкладка (U+0009 ТАБЛИЦА СИМВОЛОВ) -
\v
: вертикальная вкладка (U+000B ТАБЛИЦА ЛИНИЙ) -
\0
: нулевой символ (U+0000 NULL) (только если следующий символ не является десятичной цифрой; в противном случае это восьмеричная управляющая последовательность) -
\'
: одинарная кавычка (U+0027 АПОСТРОФ) -
\"
: двойная кавычка (U+0022 QUOTATION MARK) -
\\
: обратная косая черта (U+005C REVERSE SOLIDUS)
Все одиночные escape-символы можно \\[bfnrtv0'"\\]
.
Обратите внимание, что escape-символ \
делает специальные символы буквальными. исключение из этого правила:
'abc\
def' == 'abcdef';// true
\
, за которым следует новая строка, является не управляющей последовательностью символов, а LineContinuation
. строка не становится частью строки. Это просто способ распределить строку по нескольким строкам (например, для более удобного редактирования кода), без фактического включения в строку каких-либо новых символов строки. Я полагаю, вы могли бы подумать о \
, за которым следует новая строка в качестве управляющей последовательности для пустой строки.
Символы без специального значения также могут быть экранированы (например, '\a' == 'a'
), но это, конечно, не требуется. Однако использование \u
вне escape-последовательности Unicode или \x
вне шестнадцатеричного escape-последовательности запрещено спецификацией и приводит к тому, что некоторые механизмы выдают синтаксическую ошибку.
Примечание: IE < 9 обрабатывает ‘\v’
как 'v'
вместо вертикальной табуляции ( '\x0B'
). Если вас беспокоит межбраузерная совместимость, используйте \x0B
вместо \v
.
Следует также отметить, что escape-последовательности \v
и \0
не разрешены в строках JSON.
Восьмеричные escape-последовательности
Любой символ с кодом ниже 256
(т. е. любой символ в расширенном диапазоне ASCII) может быть экранирован с помощью его восьмеричного кода с префиксом
. (Обратите внимание, что это тот же диапазон символов, который можно экранировать с помощью шестнадцатеричных экранов.)
Чтобы использовать тот же пример, символ авторского права ( '©'
) имеет код символа 169
, что дает 251
в восьмеричное представление, поэтому вы можете записать его как '\251'
.
Восьмеричные символы могут состоять из двух, трех или четырех символов. '\1'
, '\01'
и '\001'
эквивалентны; заполнение нулями не требуется. Однако, если восьмеричный escape (например, '\1'
) является частью большей строки, и за ним сразу следует символ в диапазоне [0-7]
(например, 1
), следующий символ будет считаться частью escape-последовательности до тех пор, пока совпало не более трех цифр. Другими словами, '\12'
(один восьмеричный escape-символ, эквивалентный '\012'
) не совпадает с '\0012'
(восьмеричный escape-символ '\001'
, за которым следует неэкранированный символ '2'
). Вы можете избежать этой проблемы, просто заполняя восьмеричные escape-последовательности нулями.
Обратите внимание, что здесь есть одно исключение: сама по себе \0
не является восьмеричной управляющей последовательностью. Это выглядит как единица и даже равно
\00
и \000
, обе из которых являются восьмеричными escape-последовательностями, но если за ними не следует десятичная цифра, они действуют как односимвольные escape-последовательности. Или, в специальном жаргоне: EscapeSequence :: 0 [lookahead ∉ DecimalDigit]
\\(?:[1-7][0-7]{0,2}|[0-7]{2,3})
.Обратите внимание, что восьмеричные escape-последовательности устарели в ES5:
Предыдущие выпуски ECMAScript включали дополнительный синтаксис и семантику для указания восьмеричных литералов и восьмеричных escape-последовательностей. Они были удалены из этой версии ECMAScript. В этом ненормативном приложении представлен унифицированный синтаксис и семантика восьмеричных литералов и восьмеричных escape-последовательностей для совместимости с некоторыми старыми программами ECMAScript.
Кроме того, они выдают синтаксические ошибки в строгом режиме:
Соответствующая реализация при обработке кода строгого режима (см. 10.1.1) не может расширять синтаксис
EscapeSequence
для включенияOctalEscapeSequence
, как описано в B.1.2.
Они также запрещены в литералах шаблонов.
TL;DR Не используйте восьмеричные escape-последовательности; вместо этого используйте шестнадцатеричные escape-последовательности.
Шестнадцатеричные управляющие последовательности
Любой символ с кодом ниже 256
(т. е. любой символ в расширенном диапазоне ASCII) можно экранировать, используя его шестнадцатеричный код символа с префиксом \x
. (Обратите внимание, что это тот же диапазон символов, который можно экранировать с помощью восьмеричного escape-последовательности.)
Шестнадцатеричные escape-последовательности состоят из четырех символов. Для них требуется ровно два символа после
\x
. Если шестнадцатеричный код символа состоит только из одного символа (это касается всех кодов символов меньше 16
или 10
в шестнадцатеричном формате), вам нужно дополнить его начальным 0
.
Например, символ авторского права ( '©'
) имеет код символа 169
, что дает A9
в шестнадцатеричном формате, поэтому вы можете записать его как '\xA9'
.
Шестнадцатеричная часть этого escape-побега нечувствительна к регистру; другими словами, '\xa9'
и '\xA9'
эквивалентны.
Вы можете определить шестнадцатеричный escape-синтаксис, используя следующее регулярное выражение: \\x[a-fA-F0-9]{2}
.
Немного сбивает с толку тот факт, что в спецификации этот вид управляющей последовательности называется «шестнадцатеричной», поскольку управляющие последовательности Unicode также используют шестнадцатеричный код.
escape-последовательности Unicode
Любой символ с кодом ниже 65536
можно экранировать, используя шестнадцатеричное значение кода символа с префиксом \u
. (Как упоминалось ранее, более высокие коды символов представлены парой суррогатных символов.)
Escape-коды Unicode имеют длину шесть символов. Они требуют ровно четыре символа после \
. Если шестнадцатеричный код состоит только из одного, двух или трех символов, вам необходимо дополнить его ведущими нулями.
Символ авторского права ( '©'
) имеет код символа 169
, что дает A9
в шестнадцатеричном представлении, поэтому вы можете записать его как '\u00A9'
. Точно так же '♥'
можно записать как '\u2665'
.
Шестнадцатеричная часть такого escape-символа нечувствительна к регистру; другими словами, '\u00a9'
и '\u00A9'
эквивалентны.
Вы можете определить escape-синтаксис Unicode, используя следующее регулярное выражение: \\u[a-fA-F0-9]{4}
.
Примечание: Помимо нескольких простых escape-последовательностей, последовательности Unicode — единственные, разрешенные спецификацией JSON.
ECMAScript 6: escape-последовательности кодовых точек Unicode
ECMAScript 6 представляет новый тип escape-последовательностей в строках, а именно escape-последовательности кодовых точек Unicode. Кроме того, он определит String.fromCodePoint
и String#codePointAt
, оба из которых принимают кодовые точки, а не кодовые единицы, подобные UCS-2/UTF-16.
Когда это реализовано, любой символ можно экранировать, используя шестнадцатеричное значение его кода символа с префиксом \u{
и суффиксом }
. Это разрешено для кодовых точек до 0x10FFFF
, что является наивысшей кодовой точкой, определенной Unicode.
Экранированные кодовые точки Unicode состоят не менее чем из пяти символов. По крайней мере один шестнадцатеричный символ может быть заключен в \u{…}
. Не существует верхнего предела количества используемых шестнадцатеричных цифр (например,
'\u{000000000061}' == 'a'
), но для практических целей вам не потребуется более 6, если только вы не выполняете ненужные операции с нулями. обивка.
Тетраграмма для центрального символа ( 𝌆
) имеет кодовую точку U+1D306, поэтому ее можно записать как \u{1D306}
. Для сравнения, если бы вы использовали простые escape-последовательности Unicode для представления этого символа, вам пришлось бы записывать суррогатные половины отдельно:0013 ‘\uD834\uDF06’ .
Шестнадцатеричная часть такого escape-символа нечувствительна к регистру; другими словами, '\u{1d306}'
и '\u{1D306}'
эквивалентны.
Вы можете определить синтаксис экранирования кодовой точки Unicode, используя следующее регулярное выражение: \\u\{([0-9a-fA-F]{1,})\}
.
Управляющие escape-последовательности
В регулярных выражениях (не в строках!), любой символ с кодом больше 0
и меньше 9J в знаке вставки (поскольку 0x000A === 10
и J
— 10-я буква алфавита). Таким образом, допустимым регулярным выражением, которое соответствует этому символу, будет
/\cJ/
, например. /\cJ/.test('\n') == истина
.
Символ вставки, следующий за \c
в этом типе escape-символа, нечувствителен к регистру; другими словами, /\cJ/
и /\cj/
эквивалентны.
Вот список всех доступных escape-последовательностей управления и управляющих символов, которым они соответствуют:
Escape-последовательность | Кодовая точка Юникода |
---|---|
\ca или \ca | U+0001 НАЧАЛО ЗАГОЛОВКА |
\cB или \cb | U+0002 НАЧАЛО ТЕКСТА |
\cc или \cc | U+0003 КОНЕЦ ТЕКСТА |
\cD или \cd | U+0004 КОНЕЦ ПЕРЕДАЧИ |
\ce или \ce | U+0005 ЗАПРОС |
\cf или \cf | U+0006 ПОДТВЕРЖДЕНИЕ |
\cG или \cg | U+0007 ЗВОНОК |
\ch или \ch | U + 0008 НАЗАД |
\ci или \ci | U+0009 ТАБЛИЦА СИМВОЛОВ |
\cJ или \cj | U+000A ПЕРЕВОД СТРОКИ (НЧ) |
\cK или \ck | U+000B ТАБЛИЦА СТРОК |
\кл или \кл | U+000C ПОДАЧА ФОРМЫ (FF) |
\cM или \см | U+000D ВОЗВРАТ КАРЕТКИ (CR) |
\cN или \cn | U+000E ПЕРЕКЛЮЧЕНИЕ |
\co или \co | U+000F СМЕНА В |
\cP или \cp | U + 0010 ESCAPE КАНАЛА ПЕРЕДАЧИ ДАННЫХ |
\cQ или \cq | U + 0011 УСТРОЙСТВО УПРАВЛЕНИЯ ОДИН |
\cr или \cr | U+0012 УСТРОЙСТВО УПРАВЛЕНИЯ ДВА |
\CS или \CS | U+0013 УСТРОЙСТВО УПРАВЛЕНИЯ ТРИ |
\ct или \ct | U+0014 УСТРОЙСТВО УПРАВЛЕНИЯ ЧЕТЫРЕ |
\ у. или \ у.е. | U+0015 ОТРИЦАТЕЛЬНОЕ ПОДТВЕРЖДЕНИЕ |
\cv или \cv | U+0016 СИНХРОННЫЙ ХОЛОСТОЙ РЕЖИМ |
\cW или \cw | U+0017 КОНЕЦ БЛОКА ПЕРЕДАЧ |
\cX или \cx | U+0018 ОТМЕНА |
\cY или \cy | U+0019 КОНЕЦ СРЕДСТВА |
\cZ или \cz | U+001A ЗАМЕНА |
Вы можете определить синтаксис экранирования управления, используя следующее регулярное выражение: \\c[a-zA-Z]
.
Инструмент для экранирования символов
Я написал экранировщик строки JavaScript, который сочетает в себе эти различные виды экранирования (кроме устаревших восьмеричных экранов) и возвращает наименьшую возможную результирующую строку. Попробуйте на mothereff.in/js-escapes!
Вы можете использовать его для экранирования любого символа, но есть возможность экранировать только не-ASCII и непечатаемые символы ASCII (что, вероятно, наиболее полезно). Таким образом, вы можете легко перевернуть струны, такие как 'Ich ♥ Bücher'
в наименьший возможный эквивалент только для ASCII 'Ich \u2665 B\xFCcher'
. Когда я работал над модульными тестами Punycode.js, этот инструмент сэкономил мне довольно много времени.
Нужно экранировать строки в вашем приложении JavaScript? Библиотека JavaScript, на которой работает этот инструмент, доступна на GitHub.
4 способа преобразования строки в массив символов в JavaScript
Вот 4 способа разбить слово на массив символов. «Сплит» — наиболее распространенный и надежный способ. Но с добавлением ES6 в арсенале JS появилось больше инструментов, с которыми можно поиграть 🧰
Мне всегда нравится видеть все возможные способы решения проблемы, потому что тогда вы можете выбрать лучший способ для своего случая использования. Кроме того, когда вы увидите его всплывающее окно в чьей-то кодовой базе, вы легко его поймете 👍
- Сценарии
- Массив символов
- Специальные разделители
- Строки, содержащие эмодзи
- Предупреждение об Object.assign 9 0308️
- Вклад сообщества
- Ресурсы
Сценарии
Вместо того, чтобы анализировать плюсы и минусы каждого способа. Позвольте мне показать вам различные сценарии, в которых один предпочтительнее другого.
Массив символов
Если вы хотите разделить строку по каждому символу строки, все способы хороши и дадут вам один и тот же результат
Специальные разделители
Если вы хотите разделить строку на конкретный символ, то
разделить
путь.Остальные способы ограничены только каждым символом строки
Строки, содержащие эмодзи
Если ваши строки содержат эмодзи, то
split
илиObject.assign
может быть не лучшим выбором.Давайте посмотрим, что произойдет:
Однако, если мы используем другие способы, это работает:
Это потому, что
разделяет
, разделяя символы кодовыми единицами UTF-16, что проблематично, потому что символы эмодзи — это UTF-8. Если мы посмотрим на наш эмодзи yum'😋'
, он на самом деле состоит из 2 символов, а не из 1, как мы воспринимаем.Это так называемые графемные кластеры, когда пользователь воспринимает их как 1 единицу, но на самом деле они состоят из нескольких единиц. Более новые методы
spread
иArray.from
лучше приспособлены для их обработки и разделят вашу строку на кластеров графем 👍Предупреждение о
Object.assign
⚠️Одно замечание Object.assign
Метод Object.assign() копирует все перечисляемые собственные свойства из одного или нескольких исходных объектов в целевой объект
Ключ «копирует все перечисляемые собственные свойства».
Итак, что мы здесь делаем
Object.assign([], string)
копирует ВСЕ наши строковые свойства в наш новый массив. Это означает, что у нас есть массив ПЛЮС некоторые строковые методы.Тест TypeScript: массив результатов не является строкой
[]
типом 😱Это более очевидно, если мы используем игровую площадку TypeScript. Не стесняйтесь копировать код и вставлять в игровую площадку, где вы можете навести курсор на переменную, чтобы просмотреть типы. Поскольку это всего лишь статья, я вставлю сюда результат, чтобы вы могли следить за ней.
Однако, если мы посмотрим на тип результата
Object.assign
. Это не дает нам массив строк.Тест TypeScript: массив результатов может получить доступ к строковым свойствам 😱
Мы можем дополнительно проверить это, обратившись к свойству, которое должно быть доступно только для
String
.Значит, если я назову
жирным шрифтом
в нашем массиве, это должно сказать нам, что этого свойства не существует.Вот что мы ожидаем увидеть:
НО, если мы назовем
полужирным
в нашем якобы массиве, созданномObject.assign
, он работает 😱☝️ И это потому, что
Object.assign
копирует ВСЕ свойства исходной строки. Вот как я бы объяснил это с точки зрения не-разработчика. Вы идете в магазин, чтобы купить собаку. Но затем магазинObject.assign
продает вам собаку с крыльями дракона. Звучит очень круто, но на самом деле это домашнее животное не для аренды. Хм… Я не думаю, что это мой лучший пример. Но я думаю, вы поняли мою мысль 😂Преобразование в браузере выглядит нормально 🙂
Теперь я не думаю, что это серьезное нарушение условий сделки, потому что:
Похоже, что в браузерах есть какой-то механизм для «безопасного» выполнения Object.assign([ ], «string») и избегайте добавления методов этой строки в массив.
Спасибо @lukeshiru: за то, что поделились со мной этими знаниями 👏 Он также создал код игровой площадки TypeScript, чтобы вы могли видеть > ссылка
@CaptainOrion_: Превратить строку в массив символов, но с помощью функции карты 🤣
@HiUmesh3:
Array.