简体   繁体   中英

How to use a variable as part of a regular expression in PowerShell

I want to Select-String parts of a file path starting at a string value that is contained in a variable. Let me explain this in an abstracted example.

Let's assume this path: /docs/reports/test reports/document1.docx

Using a regular expression I can get the required string like so: '^.*(?=\\/test\\s)'

https://regex101.com/r/6mBhLX/5

The resulting string is '/test reports/document1.docx'.

Now, for this to work I have to use the literal string 'test'. However, I would like to know how to use a variable that contains 'test', eg $myString.

I already looked at How do you use a variable in a regular expression? , but I couldn't figure out how to adapt this for PowerShell.

I suggest using $([regex]::escape($myString)) inside a double quoted string literal:

$myString="[test]"
$pattern = "^.*(?=/$([regex]::escape($myString))\s)"

Or, in case you do not want to worry with additional escaping, use a regular concatenation using + operator:

$pattern = '^.*(?=/' + [regex]::escape($myString) +'\s)'

The resulting $pattern will look like ^.*(?=/\\[test]\\s) . Since the $myString variable is a literal string, you need to escape all special regex metacharacters (with [regex]::escape() ) that may be inside it for the regex engine to interpret it as literal chars.

In your case, you may use

$s = '/docs/reports/test reports/document1.docx'
$myString="test"
$pattern = "^.*(?=/$([regex]::escape($myString))\s)"
$s -replace $pattern

Result: /test reports/document1.docx

Wiktor Stribiżew's helpful answer provides the crucial pointer:

Use [regex]::Escape() in order to escape a string for safe inclusion in a regex (regular expression) so that it is treated as a literal ;
eg, [regex]::Escape('$10?') yields \\$10\\? - the characters with special meaning to a regex were \\ -escaped.

However, I suggest using '...' , ie, building the regex from single -quoted strings:

$myString='test'
$regex = '^.*(?=/' + [regex]::escape($myString) + '\s)'

Using the -f operator - $regex = '^.*(?=/{0}'\\s)' -f [regex]::Escape($myString) works too and is perhaps visually cleaner, but note that -f - unlike string concatenation with + - is culture- sensitive , which can lead to different results.

Using '...' strings in regex contexts in PowerShell is a good habit to form :

  • By avoiding "..." , you avoid additional up-front interpretation (interpolation aka expansion) of the string, which can have unexpected effects, given that $ has special meaning in both contexts: the start of a variable reference or subexpression when string-expanding, and the end-of-input marker in regexes.

  • Using "..." can be especially tricky in the replacement string of the regex-based -replace operator, where tokens such as $1 refer to capture-group results, and if you used "$1" , PowerShell would try to expand a $1 variable , which presumably doesn't exist, resulting in the empty string .


Just write the variable within double quotes ("pattern"), like this:

PS > $pattern = "^\d+\w+"
PS > "357test*&(fdnsajkfj" -match $pattern          # return true
PS > "357test*&(fdnsajkfj" -match "$pattern.*\w+$"  # return true
PS > "357test*&(fdnsajkfj" -match "$pattern\w+$"    # return false

Please have a try. :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM