Assigning an array looks like this:
PS> $x = "a", "b"
PS> $x
a
b
Now, i wanted to add a 'root string' ("r") to any element so I did this (actually i used a variable, but for the sakeness of simplicity let's just use a string here):
PS> $x = "r" + "a" , "r" + "b"
PS> $x
ra rb
Looking at the output, I didn't get the array that I expected, but a single string with a "space" (I checked: it's a 32 ascii char, so a space, not a tab or another character).
That is: the comma seems to be interpreted as a string join operator, which I couldn't find any reference to.
Even worst, I get the feeling of not understanding how the parser works here. I had a look at about_Parsing; what I found seems not to apply to this case.
Commas (,) introduce lists passed as arrays, except when the command
to be called is a native application, in which case they are
interpreted as part of the expandable string. Initial, consecutive or
trailing commas are not supported.
The first obvious fix that I came up with is the following:
PS> $x = ("r" + "a") , ("r" + "b")
PS> $x
ra
rb
Maybe there are others, and I am expecially intrested in the ones that reveal how the parser actually works. What I would like to fix the most is my knowledge of the parsing rules.
To flesh out the helpful comments on the answer:
tl;dr
Due to operator precedence, your command is parsed as "r" + ("a" , "r") + "b", causing array "a", "r" to be implicitly stringified to verbatim a r, resulting in two string concatenation operations yielding a single string with verbatim content ra rb.
Using (...) is indeed the correct way to override operator precedence.
"r" + "a" , "r" + "b"
is an expression involving operators.
Expressions are parsed in expression mode, which contrasts with argument mode; the latter applies to commands, i.e. named units of functionality that are called with shell-typical syntax (whitespace-separated arguments, quotes around simple strings optional). Arguments (parameter values) in argument mode are parsed differently from operands in expression mode, as explained in the conceptual about_Parsing help topic. Your quote about , relates to argument mode, not expression mode.
The conceptual about_Operator_Precedence help topic describes the relative precedence among operators, from which you can glean that ,, the array constructor operator has higher precedence than the + operator
Therefore, your expression is parsed as follows (using (...), the grouping operator, to make the implicit rules explicit):
"r" + ("a" , "r") + "b"
+ is polymorphic in PowerShell, and with a [string] instance as the LHS the RHS is coerced to a string too.
Therefore, array "a" , "r" is stringified, which uses PowerShell's custom array stringification, namely joining the (potentially stringified) array elements with a space.[1]
That is, the array stringifies to a string with verbatim content a r.
As an aside: The same stringification is applied in the context of string interpolation via expandable (double-quoted) strings ("..."); that is, "$("a", "r")" also yields verbatim a r
Therefore, the above is equivalent to:
"r" + "a r" + "b"
which yields verbatim ra rb.
(...) is indeed the appropriate way to ensure the desired precedence:
("r" + "a"), ("r" + "b") # -> array 'ra', 'rb'
[1] Space is the default separator character. Technically, you can override it via the $OFS preference variable, though that is rarely used in practice.
Another way to do it. The type of the first term controls what type of operation the plus performs. The first term here is an empty array. If you want the plus to do both kinds of operations, there's no getting around extra parentheses to change the operator precedence.
#() + 'ra' + 'rb'
ra
rb
Or more commonly:
'ra','rb' + 'rc'
ra
rb
rc
Related
I have a string that I want to insert dynamically a variable. Ex;
$tag = '{"number" = "5", "application" = "test","color" = "blue", "class" = "Java"}'
I want to accomplish:
$mynumber= 2
$tag = '{"number" = "$($mynumber)", "application" = "test","color" = "blue", "class" = "Java"}'
What I want is to have the variable inserted on the string, But it is not going through. I guess the '' sets all as a string. Any recomendations on how should I approach this?
thanks!
powershell test and trial and error. Also Google.
The reason your current attempt doesn't work is that single-quoted (') string literals in PowerShell are verbatim strings - no attempt will be made at expanding subexpression pipelines or variable expressions.
If you want an expandable string literal without having to escape all the double-quotes (") contained in the string itself, use a here-string:
$mynumber = 2
$tag = #"
{"number" = "$($mynumber)", "application" = "test","color" = "blue", "class" = "Java"}
"#
To add to Mathias' helpful answer:
Mistakenly expecting string interpolation inside '...' strings (as opposed to inside "...") has come up many times before, and questions such as yours are often closed as a duplicate of this post.
However, your question is worth answering separately, because:
Your use case introduces a follow-up problem, namely that embedded " characters cannot be used as-is inside "...".
More generally, the linked post is in the context of argument-passing, where additional rules apply.
Note: Some links below are to the relevant sections of the conceptual about_Quoting_Rules help topic.
In PowerShell:
only "..." strings (double-quoted, called expandable strings) perform string interpolation, i.e. expansion of variable values (e.g. "... $var" and subexpressions (e.g., "... $($var.Prop)")
not '...' strings (single-quoted, called verbatim strings), whose values are used verbatim (literally).
With "...", if the string value itself contains " chars.:
either escape them as `" or ""
E.g., with `"; note that while use of $(...), the subexpression operator never hurts (e.g. $($mynumber)), it isn't necessary with stand-alone variable references such as $mynumber:
$mynumber= 2
$tag = "{`"number`" = `"$mynumber`", `"application`" = `"test`",`"color`" = `"blue`", `"class`" = `"Java`"}"
Similarly, if you want to selectively suppress string interpolation, escape $ as `$
# Note the ` before the first $mynumber.
# -> '$mynumber = 2'
$mynumber = 2; "`$mynumber` = $mynumber"
See the conceptual about_Special_Characters help topic for info on escaping and escape sequences.
If you need to embed ' inside '...', use '', or use a (single-quoted) here-string (see next).
or use a double-quoted here-string instead (#"<newline>...<newline>"#):
See Mathias' answer, but generally note the strict, multiline syntax of here-strings:
Nothing (except whitespace) must follow the opening delimiter on the same line (#" / #')
The closing delimiter ("# / '#) must be at the very start of the line - not even whitespace may come before it.
Related answers:
Overview of PowerShell's expandable strings
Overview of all forms of string literals in PowerShell
When passing strings as command arguments, they are situationally implicitly treated like expandable strings (i.e. as if they were "..."-enclosed); e.g.
Write-Output $HOME\projects - see this answer.
Alternatives to string interpolation:
Situationally, other approaches to constructing a string dynamically can be useful:
Use a (verbatim) template string with placeholders, with -f, the format operator:
$mynumber= 2
# {0} is the placeholder for the first RHS operand ({1} for the 2nd, ...)
'"number" = "{0}", ...' -f $mynumber # -> "number" = "2", ...
Use simple string concatenation with the + operator:
$mynumber= 2
'"number" = "' + $mynumber + '", ...' # -> "number" = "2", ...
I have a string that I want to insert dynamically a variable. Ex;
$tag = '{"number" = "5", "application" = "test","color" = "blue", "class" = "Java"}'
I want to accomplish:
$mynumber= 2
$tag = '{"number" = "$($mynumber)", "application" = "test","color" = "blue", "class" = "Java"}'
What I want is to have the variable inserted on the string, But it is not going through. I guess the '' sets all as a string. Any recomendations on how should I approach this?
thanks!
powershell test and trial and error. Also Google.
The reason your current attempt doesn't work is that single-quoted (') string literals in PowerShell are verbatim strings - no attempt will be made at expanding subexpression pipelines or variable expressions.
If you want an expandable string literal without having to escape all the double-quotes (") contained in the string itself, use a here-string:
$mynumber = 2
$tag = #"
{"number" = "$($mynumber)", "application" = "test","color" = "blue", "class" = "Java"}
"#
To add to Mathias' helpful answer:
Mistakenly expecting string interpolation inside '...' strings (as opposed to inside "...") has come up many times before, and questions such as yours are often closed as a duplicate of this post.
However, your question is worth answering separately, because:
Your use case introduces a follow-up problem, namely that embedded " characters cannot be used as-is inside "...".
More generally, the linked post is in the context of argument-passing, where additional rules apply.
Note: Some links below are to the relevant sections of the conceptual about_Quoting_Rules help topic.
In PowerShell:
only "..." strings (double-quoted, called expandable strings) perform string interpolation, i.e. expansion of variable values (e.g. "... $var" and subexpressions (e.g., "... $($var.Prop)")
not '...' strings (single-quoted, called verbatim strings), whose values are used verbatim (literally).
With "...", if the string value itself contains " chars.:
either escape them as `" or ""
E.g., with `"; note that while use of $(...), the subexpression operator never hurts (e.g. $($mynumber)), it isn't necessary with stand-alone variable references such as $mynumber:
$mynumber= 2
$tag = "{`"number`" = `"$mynumber`", `"application`" = `"test`",`"color`" = `"blue`", `"class`" = `"Java`"}"
Similarly, if you want to selectively suppress string interpolation, escape $ as `$
# Note the ` before the first $mynumber.
# -> '$mynumber = 2'
$mynumber = 2; "`$mynumber` = $mynumber"
See the conceptual about_Special_Characters help topic for info on escaping and escape sequences.
If you need to embed ' inside '...', use '', or use a (single-quoted) here-string (see next).
or use a double-quoted here-string instead (#"<newline>...<newline>"#):
See Mathias' answer, but generally note the strict, multiline syntax of here-strings:
Nothing (except whitespace) must follow the opening delimiter on the same line (#" / #')
The closing delimiter ("# / '#) must be at the very start of the line - not even whitespace may come before it.
Related answers:
Overview of PowerShell's expandable strings
Overview of all forms of string literals in PowerShell
When passing strings as command arguments, they are situationally implicitly treated like expandable strings (i.e. as if they were "..."-enclosed); e.g.
Write-Output $HOME\projects - see this answer.
Alternatives to string interpolation:
Situationally, other approaches to constructing a string dynamically can be useful:
Use a (verbatim) template string with placeholders, with -f, the format operator:
$mynumber= 2
# {0} is the placeholder for the first RHS operand ({1} for the 2nd, ...)
'"number" = "{0}", ...' -f $mynumber # -> "number" = "2", ...
Use simple string concatenation with the + operator:
$mynumber= 2
'"number" = "' + $mynumber + '", ...' # -> "number" = "2", ...
I just came across some code that looks like this:
var msg:String = "";
msg ?= err["ErrorMessage"].text;
The err variable is from SwiftyXMLParser from what I can see in the code. I'm at a loss about the meaning of the ?= (questionmark-equals) operator. I cannot find documentation about it. What is it doing?
This question is a quite interesting topic in Swift language.
In other programming languages, it is closed to operator overloading whereas in Swifty terms, it is called Custom Operators. Swift has his own standard operator, but we can add additional operator too. Swift has 4 types of operators, among them, first 3 are available to use with custom operators:
Infix: Used between two values, like the addition operator (e.g. 1 + 2)
Prefix: Added before a value, like the negative operator (e.g. -3).
Postfix: Added after a value, like the force-unwrap operator (e.g. objectNil!)
Ternary: Two symbols inserted between three values.
Custom operators can begin with one of the ASCII characters /, =, -, +, !, *, %, <, >, &, |, ^, ?, or ~, or one of the Unicode characters.
New operators are declared at a global level using the operator keyword, and are marked with the prefix, infix or postfix modifiers:
Here is a sample example in the playground[Swift 4].
infix operator ?=
func ?= (base: inout String, with: String)
{
base = base + " " + with
}
var str = "Stack"
str ?= "Overflow"
print(str)
Output:
Stack Overflow
Please check the topic name Advanced operator in apple doc.
This seems easy, but after searching, I have come up empty-handed.
How can I divide two decimals in powershell?
204.50 / 1,917.75
Throws the following error:
Method invocation failed because [System.Object[]] does not contain a method named 'op_Division'.
At line:1 char:1
+ 204.50 / 1,917.75
+ ~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (op_Division:String) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
Try leaving the comma out. What you've typed looks like 204.50 divided by 1 and then 917.75
Walter Mitty's answer is an effective solution.
To explain why 204.50 / 1,917.75 failed:
PowerShell number literals (a) always use . as the decimal mark, irrespective of the current culture, and (b) do not support use of a thousands separator (such as ,).
This implies that 1,917.75 is not recognized as a number literal, which begs the question (kinda): how is it parsed?
, is the array-construction operator in PowerShell: that is, tokens separated by , constitute the elements of an array.
Thus, 1,917.75, is the equivalent of #( 1, 917.75 ): a 2-element array containing [int] 1 and [double] 917.75.
, has higher precedence than /, the division operator, so that 204.50 / 1,917.75 is the equivalent of:
204.50 / #( 1, 917.75 )
That is, PowerShell tries to divide [double] literal 204.50 by array #( 1, 917.75 )
Since PowerShell doesn't know how to divide anything by an array (generically represented in PowerShell as [System.Object[]]), you get the following error message:
Method invocation failed because [System.Object[]] does not contain a method named 'op_Division'.
That is, PowerShell looks for a way to apply division operator / (op_Division) to array operands, and since that isn't defined, an error occurs.
As an aside: PowerShell does overload some operators to work with arrays, but only if the array is on the LHS (the left-hand side operand).
Operators -eq / ne, -like / -notlike, -match / -notmatch (do let me know if I'm missing any) accept an array as the LHS and a scalar as the RHS, in which case the operator acts as a filter:
The operator is applied individually to the elements of the LHS (against the scalar on the RHS), and the subset of elements for which the operation returns $true is returned as a subarray of the input array; e.g.:
#( 'donald trump', 'hillary clinton', 'gary johnson' ) -notmatch 'trump'
outputs #( 'hillary clinton', 'gary johnson' ), the subarray of the input containing only those elements that do not contain the substring trump.
I have the following code:
val z: String = tree.symbol.toString
z match {
case "method +" | "method -" | "method *" | "method ==" =>
println("no special op")
false
case "method /" | "method %" =>
println("we have the special div operation")
true
case _ =>
false
}
Is it possible to create a match for the primitive operations in Scala:
"method *".matches("(method) (+-*==)")
I know that the (+-*) signs are used as quantifiers. Is there a way to match them anyway?
Thanks from a avidly Scala scholar!
Sure.
val z: String = tree.symbol.toString
val noSpecialOp = "method (?:[-+*]|==)".r
val divOp = "method [/%]".r
z match {
case noSpecialOp() =>
println("no special op")
false
case divOp() =>
println("we have the special div operation")
true
case _ =>
false
}
Things to consider:
I choose to match against single characters using [abc] instead of (?:a|b|c).
Note that - has to be the first character when using [], or it will be interpreted as a range. Likewise, ^ cannot be the first character inside [], or it will be interpreted as negation.
I'm using (?:...) instead of (...) because I don't want to extract the contents. If I did want to extract the contents -- so I'd know what was the operator, for instance, then I'd use (...). However, I'd also have to change the matching to receive the extracted content, or it would fail the match.
It is important not to forget () on the matches -- like divOp(). If you forget them, a simple assignment is made (and Scala will complain about unreachable code).
And, as I said, if you are extracting something, then you need something inside those parenthesis. For instance, "method ([%/])".r would match divOp(op), but not divOp().
Much the same as in Java. To escape a character in a regular expression, you prefix the character with \. However, backslash is also the escape character in standard Java/Scala strings, so to pass it through to the regular expression processing you must again prefix it with a backslash. You end up with something like:
scala> "+".matches("\\+")
res1 : Boolean = true
As James Iry points out in the comment below, Scala also has support for 'raw strings', enclosed in three quotation marks: """Raw string in which I don't need to escape things like \!""" This allows you to avoid the second level of escaping, that imposed by Java/Scala strings. Note that you still need to escape any characters that are treated as special by the regular expression parser:
scala> "+".matches("""\+""")
res1 : Boolean = true
Escaping characters in Strings works like in Java.
If you have larger Strings which need a lot of escaping, consider Scala's """.
E. g. """String without needing to escape anything \n \d"""
If you put three """ around your regular expression you don't need to escape anything anymore.