What are the actual uses of ES6 Raw String Access?
Asked Answered
M

7

35

What are the actual uses of String.raw Raw String Access introduced in ECMAScript 6?

// String.raw(callSite, ...substitutions)

function quux (strings, ...values) {
    strings[0] === "foo\n"
    strings[1] === "bar"
    strings.raw[0] === "foo\\n"
    strings.raw[1] === "bar"
    values[0] === 42
}

quux `foo\n${ 42 }bar`

String.raw `foo\n${ 42 }bar` === "foo\\n42bar"

I went through the below docs.

http://es6-features.org/#RawStringAccess

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/template_strings

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/raw

http://www.2ality.com/2015/01/es6-strings.html

https://msdn.microsoft.com/en-us/library/dn889830(v=vs.94).aspx

The only the thing that I understand, is that it is used to get the raw string form of template strings and used for debugging the template string.

When this can be used in real time development? They were calling this a tag function. What does that mean?

What concrete use cases am I missing?

Monoculture answered 13/1, 2016 at 17:6 Comment(2)
How about dynamic regular expressions? Instead of RegExp('\\\\') you can write RegExp(String.raw`\\`) (+ the dynamic part of course), which can make the expression easier to understand and maintain. Or in more general: Whenever you want the backslash not be considered as the (string) escape character. Python and PHP have raw string literals (r'...', '..') for such cases, which is basically the same thing.Aer
@FelixKling awesome :OMcinnis
C
21

The best, and very nearly only, use case for String.raw I can think of is if you're trying to use something like Steven Levithan's XRegExp library that accepts text with significant backslashes. Using String.raw lets you write something semantically clear rather than having to think in terms of doubling your backslashes, just like you can in a regular expression literal in JavaScript itself.

For instance, suppose I'm doing maintenance on a site and I find this:

var isSingleUnicodeWord = /^\w+$/;

...which is meant to check if a string contains only "letters." Two problems: A) There are thousands of "word" characters across the realm of human language that \w doesn't recognize, because its definition is English-centric; and B) It includes _, which many (including the Unicode consortium) would argue is not a "letter."

So if we're using XRegExp on the site, since I know it supports \pL (\p for Unicode categories, and L for "letter"), I might quickly swap this in:

var isSingleUnicodeWord = XRegExp("^\pL+$"); // WRONG

Then I wonder why it didn't work, facepalm, and go back and escape that backslash, since it's being consumed by the string literal.

Easy enough in that simple regex, but in something complicated, remembering to double all those backslashes is a maintenance pain. (Just ask Java programmers trying to use Pattern.)

Enter String.raw:

let isSingleUnicodeWord = XRegExp(String.raw`^\pL+$`);

Example:

let isSingleUnicodeWord = XRegExp(String.raw`^\pL+$`); // L: Letter
console.log(isSingleUnicodeWord.test("Русский"));      // true
console.log(isSingleUnicodeWord.test("日本語"));        // true
console.log(isSingleUnicodeWord.test("العربية"));      // true
console.log(isSingleUnicodeWord.test("foo bar"));      // false
<script src="https://cdnjs.cloudflare.com/ajax/libs/xregexp/3.1.1/xregexp-all.min.js"></script>

Now I just kick back and write what I mean. I don't even really have to worry about ${...} constructs used in template literals to do substitution, because the odds of my wanting to apply a quantifier {...} to the end-of-line assertion ($) are...low. So I can happily use substitutions and still not worry about backslashes. Lovely.


Having said that, though, if I were doing it a lot, I'd probably want to write a function and use a tagged template instead of String.raw itself. But it's surprisingly awkward to do correctly:

// My one-time tag function
function xrex(strings, ...values) {
  let raw = strings.raw;
  let max = Math.max(raw.length, values.length);
  let result = "";
  for (let i = 0; i < max; ++i) {
    if (i < raw.length) {
      result += raw[i];
    }
    if (i < values.length) {
      result += values[i];
    }
  }
  console.log("Creating with:", result);
  return XRegExp(result);
}

// Using it, with a couple of substitutions to prove to myself they work
let category = "L";                                // L: Letter
let maybeEol = "$";
let isSingleUnicodeWord = xrex`^\p${category}+${maybeEol}`;
console.log(isSingleUnicodeWord.test("Русский"));  // true
console.log(isSingleUnicodeWord.test("日本語"));    // true
console.log(isSingleUnicodeWord.test("العربية"));  // true
console.log(isSingleUnicodeWord.test("foo bar"));  // false
<script src="https://cdnjs.cloudflare.com/ajax/libs/xregexp/3.1.1/xregexp-all.min.js"></script>

Maybe the hassle is worth it if you're using it in lots of places, but for a couple of quick ones, String.raw is the simpler option.

Cyzicus answered 7/8, 2016 at 17:16 Comment(1)
Not just the XRegExp library, also just normal js regex with template literals. e.g: capture literal parens, rather than needing to escape the slashes escaping the parens new RegExp(String.raw`function\(${ok}\)`) vs new RegExp(`function\\(${ok}\\)`)Horsecar
M
5

First, a few things:

  • Template strings is old name for template literals.
  • A tag is a function.
  • String.raw is a method.
  • String.raw `foo\n${ 42 }bar\` is a tagged template literal.
  • Template literals are basically fancy strings.
  • Template literals can interpolate.
  • Template literals can be multi-line without using \.
  • String.raw is required to escape the escape character \.

Try putting a string that contains a new-line character \n through a function that consumes newline character.

console.log("This\nis\nawesome"); // "This\nis\nawesome"
console.log(String.raw`This\nis\nawesome`); // "This\\nis\\nawesome"

If you are wondering, console.log is not one of them. But alert is. Try running these through http://learnharmony.org/ .

alert("This\nis\nawesome");
alert(String.raw`This\nis\nawesome`);

But wait, that's not the use of String.raw.

Possible uses of String.raw method:

  • To show string without interpretation of backslashed characters (\n, \t) etc.
  • To show code for the output. (As in example below)
  • To be used in regex without escaping \.
  • To print windows director/sub-directory locations without using \\ to much. (They use \ remember. Also, lol)

Here we can show output and code for it in single alert window:

alert("I printed This\nis\nawesome with " + Sring.raw`This\nis\nawesome`);

Though, it would have been great if It's main use could have been to get back the original string. Like:

var original = String.raw`This    is     awesome.`;

where original would have become: This\tis \tawesome.. This isn't the case sadly.

References:

Meg answered 11/2, 2016 at 15:23 Comment(2)
Nice one @anubhav sainiMonoculture
The only use-case for String.raw I see above (the question Venkatraman asked) is the regex one (which Felix Kling flagged up in a comment about a month earlier), and of course regex literals make that case largely unnecessary. You'd really only need it if you were taking a string and adding a lot of regex around it that involved backslashes and running it through new RegExp. So that's a use case, just a really rare one. Do you know of any others?Cyzicus
G
3

Template strings can be useful in many situations which I will explain below. Considering this, the String.raw prevents escapes from being interpreted. This can be useful in any template string in which you want to contain the escape character but do not want to escape it. A simple example could be the following:

var templateWithBackslash = String.raw `someRegExp displayed in template /^\//`

There are a few things inside that are nice to note with template strings.

  1. They can contain unescaped line breaks without problems.
  2. They can contain "${}". Inside these curly braces the javascript is interpreted instead.

(Note: running these will output the result to your console [in browser dev tools])

Example using line breaks:

var myTemplate = `
<div class="myClass">
  <pre>
    My formatted text
    with multiple lines
    {
      asdf: "and some pretty printed json"
    }
  </pre>
</div>
`
console.log(myTemplate)

If you wanted to do the above with a normal string in Javascript it would look like the following:

var myTemplate = "\
<div class="myClass">\
  <pre>\
    My formatted text\
    with multiple lines\
    {\
      asdf: "and some pretty printed json"\
    }\
  </pre>\
</div>"
console.log(myTemplate)

You will notice the first probably looks much nicer (no need to escape line breaks).

For the second I will use the same template string but also insert the some pretty printed JSON.

var jsonObj = {asdf: "and some pretty printed json", deeper: {someDeep: "Some Deep Var"}}
var myTemplate = `
<div class="myClass">
  <pre>
    My formatted text
    with multiple lines
    ${JSON.stringify(jsonObj, null, 2)}
  </pre>
</div>
`
console.log(myTemplate)
Geffner answered 14/1, 2016 at 0:51 Comment(2)
Thanks @Gobinlord, but my question here is about String.raw method not Template StringsMonoculture
Sorry, actually all it does is just prevent interpretation of escape char ('\'). Thats all it does so in any template you want to use '\' in then you can use String.raw instead of escaping manually. That's all really... simple. I will add this into answer.Geffner
B
3

In NodeJS it is extremely handy when it comes to filepath handling:

var fs=require('fs');
var s =  String.raw`C:\Users\<username>\AppData\Roaming\SomeApp\someObject.json`;
var username = "bob"
s=s.replace("<username>",username)
fs.readFile(s,function(err,result){
    if (err) throw error;
    console.log(JSON.parse(result))
})

It improves readability of filepaths on Windows. \ is also a fairly common separator, so I can definitely see why it would be useful in general. However it is pretty stupid how \ still escapes `... So ultimately:

String.raw`C:\Users\` //#==> C:\Users\`
console.log(String.raw`C:\Users\`) //#==> SyntaxError: Unexpected end of input.
Brass answered 25/5, 2017 at 10:7 Comment(2)
\u is also still parsed as the beginning of a Unicode character code even in a String.raw, so its usefulness seems extremely limited indeed. If you have a directory starting with a lower-case u somewhere in that Windows-style path, you'll have to escape it again.Caucasoid
The behaviour that @DanielSaner is talking about was fixed in ES2018 via the Template Literal Revision proposal.Harmsworth
D
1

The Use

(Requisite knowledge: tstring §.)

Instead of:

console.log(`\\a\\b\\c\\n\\z\\x12\\xa9\\u1234\\u00A9\\u{1234}\\u{00A9}`); 

.you can:

console.log(String.raw`\a\b\c\n\z\x12\xa9\u1234\u00A9\u{1234}\u{00A9}`);

"Escaping"

<\\u> is fine, yet <\u> needs "escaping", eg:

console.log(String.raw`abc${'\\u'}abc`);

.Dit <\\x>, <\x>, <console.log(String.raw`abc${`\\x`}abc`)>;

.<\`>, <`>, <console.log(String.raw`abc${`\``}abc`)>;

.<\${>, <${&>, <console.log(String.raw`abc${`$\{`}abc`)>;

.<\\1> (till <\\7>), <\1>, <console.log(String.raw`abc${`\\1`}abc`)>;

.<\\>, endunit <\>, <console.log(String.raw`abc${`\\`}`)>.


Nb

There's also a new "latex" string. Cf §.

Droplight answered 17/6, 2017 at 17:44 Comment(0)
S
1

In addition to its use as a tag, String.raw is also useful in implementing new tag functions as a tool to do the interleaving that most people do with a weird loop. For example, compare:

function foo(strs, ...xs) {
    let result = strs[0];
    for (let i = 0; i < xs.length; ++i) {
      result += useFoo(xs[i]) + strs[i + 1];
    }
    return result;
}

with

function foo(strs, ...xs) {
    return String.raw({raw: strs}, ...xs.map(useFoo));
}
Startling answered 11/6, 2021 at 19:57 Comment(0)
S
0

I've found it to be useful for testing my RegExps. Say I have a RegExp which should match end-of-line comments because I want to remove them. BUT, it must not match source-code for a regexp like /// . If your code contains /// it is not the start of an EOL comment but a RegExp, as per the rules of JavaScript syntax.

I can test whether my RegExp in variable patEOLC matches or doesn't /// with:

String.raw`/\//` .match (patEOLC)

In other words it is a way to let my code "see" code the way it exists in source-code, not the way it exists in memory after it has been read into memory from source-code, with all backslashes removed.

It is a way to "escape escaping" but without having to do it separately for every backslash in a string, but for all of them at the same time.

It is a way to say that in a given (back-quoted) string backslash shall behave just like any other character, it has no special meaning or interpretation.

Sectarianize answered 11/9, 2018 at 21:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.