String.raw: некоторые возможности и ограничения

в 8:50, , рубрики: escape, javascript, node.js, regular expressions, V8, windows, windows registry, браузеры, Регулярные выражения, экранирование

I. Возможности

Когда я прочитал на MDN про String.raw(): «The static String.raw() method is a tag function of template literals, similar to the r prefix in Python or the @ prefix in C# for string literals» — я здорово обрадовался, потому что мне часто не хватало в JavaScript чего-то вроде одиночных кавычек в Perl.

Я сразу придумал несколько видов использования и стал активно применять их в скриптах.

1. Определение путей к файлам Windows без двойного экранирования.

const r = String.raw;

const test_module = require(r`e:DOCprgjsnode-libtest.js`);

2. Определение путей к ключам реестра Windows.

const r = String.raw;

const Winreg = require('winreg');

const regKey = new Winreg({
  hive: Winreg.HKCU,
  key: r`SoftwareMPC-HCMPC-HCSettings`
});

3. Создание сложных регулярных выражений из составных литералов.

См. пример кода в одной из недавних статей.

II. Ограничения

Однако со временем я стал натыкаться на неожиданные ограничения. Написав об одном из них в багтрекер V8, я получил отрезвляющее объяснение. Оказывается, хоть String.raw и выдаёт строку без интерпретации экранированных литералов, на стадии парсинга кода анализатор всё равно требует, чтобы литералы соответствовали правилам. Из этого следуют неочевидные ограничения для упомянутых случаев применения.

1. После обратной косой черты не могут следовать символы x или u.

Следующий код выдаёт ошибку Uncaught SyntaxError: Invalid hexadecimal escape sequence:

console.log(String.raw`с:x.js`);

Следующий код выдаёт ошибку Uncaught SyntaxError: Invalid Unicode escape sequence:

console.log(String.raw`с:u.js`);

При том, что правильные сочетания всё равно сериализируются неинтерпретированными:

console.log(String.raw`x61`);
//x61
console.log(String.raw`u0061`);
//u0061

Простых способов решить проблему я не нашёл:

console.log(String.raw`с:\x.js`);
// с:\x.js
console.log(String.raw`с:\x78.js`);
// с:\x78.js
console.log(String.raw`с:${'x'}.js`);
// с:${'x'}.js
console.log(String.raw`с:\${'x'}.js`);
// с:\x.js

console.log(String.raw`с:\u.js`);
// с:\u.js
console.log(String.raw`с:\x75.js`);
// с:\x75.js
console.log(String.raw`с:${'u'}.js`);
// с:${'u'}.js
console.log(String.raw`с:\${'u'}.js`);
// с:\u.js

Работающие решения настолько сложны, что проще будет вернуться к использованию обычных кавычек с двойным экранированием:

console.log(String.raw`с:${'\'}x.js`);
// с:x.js
console.log(String.raw`с:${'\'}u.js`);
// с:u.js

Остальные совпадения с экранированными литералами трудностей не вызывают и отображаются буквально:

console.log(String.raw`с:ab cd`);
console.log(String.raw`с:ab' cd`);
console.log(String.raw`с:ab" cd`);
console.log(String.raw`с:ab\ cd`);
console.log(String.raw`с:abn cd`);
console.log(String.raw`с:abr cd`);
console.log(String.raw`с:abv cd`);
console.log(String.raw`с:abt cd`);
console.log(String.raw`с:abb cd`);
console.log(String.raw`с:abf cd`);

2. Нет простого способа включить в строку сам символ `.

Этот символ иногда заменяет английский апостроф, а также используется в некоторых системах транслитерации.

Ожидаемая ошибка Uncaught SyntaxError: missing ) after argument list:

console.log(String.raw`с:John`s.js`);

Неработающие решения:

console.log(String.raw`с:John`s.js`);
// с:John`s.js
console.log(String.raw`с:Johnx60s.js`);
// с:Johnx60s.js

Неоправданная сложность:

console.log(String.raw`с:John${'`'}s.js`);
// с:John`s.js

3. Нет простого способа создать строку с обратной косой чертой в самом конце.

Ожидаемая ошибка Uncaught SyntaxError: Unterminated template literal:

console.log(String.raw`с:`);

Неработающие решения:

console.log(String.raw`с:\`);
// с:\
console.log(String.raw`с:x5c`);
// с:x5c

Неоправданная сложность:

console.log(String.raw`с:${'\'}`);
// с:

III. Сравнение с другими языками

Соответствующие средства упомянутых в начале заметки языков работают, как и ожидалось, что можно проверить, например, здесь.

C#:

String.raw: некоторые возможности и ограничения - 1

Perl:

String.raw: некоторые возможности и ограничения - 2

Python:

String.raw: некоторые возможности и ограничения - 3

Если вы нашли другие интересные способы применения String.raw, столкнулись с другими неожиданными ограничениями или придумали элегантные способы их обхода, поделитесь, пожалуйста.

Автор: vmb

Источник

Поделиться новостью

* - обязательные к заполнению поля