Sunday, March 3, 2013

PowerShell string literals and formating


Basics

String literals are one of essential constructs of PS. There are lot of ways to create and manage them.

There is a major difference between single and double quoted string. Single quoted literals are not processed by PowerShell at all, so you can not add variables, escaped characters and other cool stuff to them.
  1. $var = 'Append'  
  2.   
  3. # Substitution:  
  4. Write-Host 'No substitution: $var' # No substitution: $var  
  5. Write-Host "Substitution: $var"    # Substitution: Append  
  6.   
  7. # Double quote char to add same quotes as literal quoted:  
  8. Write-Host 'Don''t forget that " is originally inch character' # Single quote doubled  
  9. Write-Host "Don't forget that "" is originally inch character" # Double quote doubled 
  10.  
  11. # To use escape chars escape them with ` character. 
  12. # Find it on [~] key, it is like small back slash. 
  13. # It works only with double quoted strings 
  14. Write-Host "First line`r`nSecong line"  # line break 
  15. Write-Host "First`tSecond"              # tabulation  
The benefit of single quoted strings is easy way to create string with lots of '$', '`' and '"' characters in it.

Expression substitution

First advanced feature I want to mention is a complex expression substitutions. You are not limited with simple variable substitution in double quoted strings. You can add expressions of any complexity to your string, and they will be executed. Just wrap expression inside double quoted string with $( ... ):
  1. $arr = @(4, 8, 15, 16, 23, 42)  
  2. $hashtable = @{  
  3.     Name = "James";  
  4.     Surname = 'Bond';  
  5. }  
  6. Function Add-Numbers ($a,$b) {  
  7.     $a + $b  
  8. }  
  9.   
  10. Write-Host "Answer to the Ultimate Question of Life is $($arr[5])"  
  11. Write-Host "My name is $($hashtable.Surname), $($hashtable.Name) $($hashtable.Surname)."  
  12. Write-Host "13 + 43 = $(Add-Numbers 13 41)"  

Here-strings

When you want to add some big literal with line breaks, both single and double quotes in it (great example is XML) you do not need to shield all them and change line breaks to "`r`n" stuff. There is such thing as 'here-strings' in PowerShell. They should start with @" and line break and should end with line break "@.
  1. # Notice that line break after @" and before "@ is not included to string  
  2. $hereString = @" 
  3. First line 
  4. Quotes of both types: " and '  
  5. Grave accent: `  
  6. Last line  
  7. "@  

Format string

You can use ordinary format string via special keyword -f. As in .NET you can use format item to add some additional parameters to format:
  1. Write-Host ( 'My name is {1}, {0} {1}' -f 'James''Bond' )  
  2. # My name is Bond, James Bond  
  3.   
  4. Write-Host ( 'Double formatting {0:F3}' -f 1.2 )  
  5. # Double formatting 1,200  
  6.   
  7. Write-Host ( 'DateTime format {0:MM/dd/yy H:mm:ss zzz}' -f [DateTime]::Now)  
  8. # DateTime format 03.03.13 21:32:34 +02:00  
Please notice, that you can not feed other cmdlets result of format without round brackets, otherwise it will be interpreted as attribute name of feeded cmdlet:
  1. # Error!  
  2. Write-Host 'Simple {0}' -f 'format'  
Here -f will be threated like Write-Host -Foreground attribute, so just wrap it with ( ) as in examples above.

Performance

In rare cases single quoted string can give you performance boost if you prefer concatenation of single quoted strings to substitution inside of double quoted string. Try this example, and you will find, that concatenation is almost two times faster:
  1. $s = New-Object System.Diagnostics.Stopwatch  
  2.   
  3. $s.Start()  
  4. for ($i = 0; $i -lt 1000000; $i++) {  
  5.     $var = 'world'  
  6.     $a = "Hello $var"  
  7. }  
  8. $s.Stop()  
  9. Write-Host 'Double quotes with substitution: ' + $s.Elapsed  
  10.   
  11.   
  12. $s.Reset()  
  13. $s.Start()  
  14. for ($i = 0; $i -lt 1000000; $i++) {  
  15.     $var = 'world'  
  16.     $a = 'Hello ' + $var  
  17. }  
  18. $s.Stop()  
  19. Write-Host 'Single quotes and concatenation: ' + $s.Elapsed