String Interpolation When Not Using a String Literal

String interpolation when not using a string literal

Actually Ruby has functionality very similar to John's Python example:

$ irb
>> greeting = 'hello %s, my name is %s!'
>> interpolated = greeting % ['Mike', 'John']
=> "hello Mike, my name is John!"
>>

This is also useful if your argument is an array constant. If you must use #{} style interpolation you could use eval:

>> greeting = 'hi #{name}'    # notice name is not defined yet
>> name = "mike"
>> eval '"' + greeting + '"'

The eval approach is going to be much slower than using % style interpolation, so it's a trade-off.

How do I use string interpolation with string literals?

You should add () because : is used also for string formatting:

string heading = $"Weight in {(imperial ? "lbs" : "kg")}";

Why does interpolating a const string result in a compiler error?

Interpolated strings are simply converted to calls to string.Format. So your above line actually reads

private const string WEB_API_PROJECT = string.Format("{0}project.json", WEB_API_ROOT);

And this is not compile time constant as a method call is included.


On the other hand, string concatenation (of simple, constant string literals) can be done by the compiler, so this will work:

private const string WEB_API_ROOT = "/private/WebApi/";
private const string WEB_API_PROJECT = WEB_API_ROOT + "project.json";

or switch from const to static readonly:

private static readonly string WEB_API_PROJECT = $"{WEB_API_ROOT}project.json";

so the string is initialized (and string.Format called) at the first access to any member of the declaring type.

Directory string interpolation for file creation

Check out the documentation on string interpolation.

The $ special character identifies a string literal as an interpolated string. An interpolated string is a string literal that might contain interpolation expressions. When an interpolated string is resolved to a result string, items with interpolation expressions are replaced by the string representations of the expression results. This feature is available starting with C# 6.

So, in order to get an interpolated string, your string literal needs to begin with the $ character.

string keydir = $"{dName}:\b4nk.key";

You should also check out the documentation on verbatim strings. Specifically, the second item in the list which describes verbatim string literals.

To indicate that a string literal is to be interpreted verbatim. The @ character in this instance defines a verbatim string literal. Simple escape sequences (such as "\" for a backslash), hexadecimal escape sequences (such as "\x0041" for an uppercase A), and Unicode escape sequences (such as "\u0041" for an uppercase A) are interpreted literally. Only a quote escape sequence ("") is not interpreted literally; it produces one double quotation mark. Additionally, in case of a verbatim interpolated string brace escape sequences ({{ and }}) are not interpreted literally; they produce single brace characters. The following example defines two identical file paths, one by using a regular string literal and the other by using a verbatim string literal. This is one of the more common uses of verbatim string literals.

It appears you've added the special @ character to the name of your variable, keydir. Using the @ character at the beginning of a variable name would allow you to use a keyword as a variable name, for example if you wanted a variable named class you could name it @class. Placing @ at the start of the variable name will not cause it to be interpreted literally if it is a string, you have to place it at the front of the string literal.

You can combine the $ and @ characters to get an interpolated, verbatim string literal:

string keydir = $@"{dName}:\b4nk.key";

In Python 3.6, why don't string literals (using the same quote type) work inside interpolated strings?

This has nothing to do with interpolated strings. An interpolated string is read the same as any other string literal* and then interpolated, and you can't put unescaped quote characters in the middle of any string:

>>> msg = 'Hello {table['username']}'
File "<stdin>", line 1
'Hello {table['username']}'
^
SyntaxError: invalid syntax
>>> msg = 'Hello 'world''
File "<stdin>", line 1
msg = 'Hello 'world''
^
SyntaxError: invalid syntax

This is exactly why we have a choice of two different quote characters—and, when that isn't enough, triple-quoted strings. And of course escaping.

So, why can't Python be smarter here? Think about what "smarter" would mean. Assuming it can't read your mind, it would have to parse every possible way that pairs of quotes could be matched up if some of them were skipped and then figure out which one made for a valid result. That might not seem too bad for a simple one-liner at the interactive interpreter, but if it had to do that across an entire file, every time you run a non-trivial script or import a module with more than a few quotes in it, it would take minutes to try all the parses, and the result could well be ambiguous anyway.

Could they instead add special rules for handling quotes only in interpolated strings, only inside currently-open braces (but not double braces, of course, because those are escapes), and so on?

Sure, That wouldn't make the parser exponential, just more complicated. But more complicated is not good either.

The fact that Python has a simple set of rules that anyone can knock out a LL(1) implementation of—and, maybe even more importantly, that anyone can keep in their heads and work through—is a major feature of the language as compared to, say, C++. So every time there's a tradeoff between nice syntactic sugar vs. keeping the parser simple, it has to be thought through, and the answer is always keeping the parser simpler. In fact, this was an explicit decision in the Python 3 transition:

Simple is better than complex. This idea extends to the parser. Restricting Python's grammar to an LL(1) parser is a blessing, not a curse. It puts us in handcuffs that prevent us from going overboard and ending up with funky grammar rules like some other dynamic languages that will go unnamed, such as Perl.

Also, of course, that would be a difference between f-strings and str.format, which would be another rule to learn, and to relearn every time you come back to Python after a few months away. Which is a different rule from the Zen: Special cases aren't special enough to break the rules.

String Interpolation with format variable

No, you can't use string interpolation with something other than a string literal as the compiler creates a "regular" format string even when you use string interpolation.

Because this:

string name = "bar";
string result = $"{name}";

is compiled into this:

string name = "bar";
string result = string.Format("{0}", name);

the string in runtime must be a "regular" format string and not the string interpolation equivalent.

You can use the plain old String.Format instead.

String interpolation issues

The problem with this line

Assert.AreEqual(formatted, $"{{countdown|{date:o}}}");

is that you have 3 curly quotes after the format string of the variable to be escaped and it starts escaping from left to right, therefore it treats the first 2 curly quotes as part of the format string and the third curly quote as the closing one.

So it transforms o in o} and the it's unable to interpolate it.

This should work

Assert.AreEqual(formatted, $"{{countdown|{date:o}"+"}");

Notice that the simpler $"{date}}}" (i.e. 3 curls after the variable without a format string) does work because it recognizes that the first curly quote is the closing one, while the interpretation of the format specifier after the : breaks the correct closing parenthesis identification.

To prove that the format string is escaped like a string, consider that the following

$"{date:\x6f}"

is treated as

$"{date:o}"

Finally, it is perfectly possible that the double escaped curly quotes are part of a custom date format, so it is absolutely reasonable the behaviour of the compiler. Again, a concrete example

$"{date:MMM}}dd}}yyy}" // it's a valid feb}09}2017

Parsing is a formal process based on expression grammar rules, can't be done by just glancing at it.

String Escaping With $ Interpolation and @ Encoding

When using @, a double quote inside a string is to be represented as "":

var htmlEmail = $@"
<p>Dear {name},</p>
<p>Please click this awesome <a href=""google.com"">link.</a></p>
";

.NET Fiddle: https://dotnetfiddle.net/fESnd1

Explanation:

The @ causes the compiler to take strings literally instead of interpreting them. With the @ linebreaks inside string literals are allowed, and the backslash \ becomes a normal string character instead of an escape character, causing e.g. @"\r\n" to be a string of four characters: \, r, \ and n. This made it necessary to use another way to include a double quote, which became "".

Reference: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/verbatim



Related Topics



Leave a reply



Submit