Reputation: 153
There are controls on the form that need to be searched inside the function, for this I decided to use Controls.Find
, the input of the function is $name
. In this case, the search works among the TextBox
and add to the array for further work. TextBox
names are represented as IPTextBox1
, IPTextBox2
, etc. As I wrote and how it does not work (NetworkForm
is a form that contains all controls):
$TextBoxes = $NetworkForm.Controls.Find('/^([regex]::escape($name))[A-Z]{1}[a-z]{3}[A-Z]{1}[a-z]{2}.{1}$/', 1)
Upvotes: 2
Views: 87
Reputation: 437278
To answer the generic question in the title:
The safest way to embed an arbitrary variable value in a regex is:
to first escape the value with [regex]::Escape($var)
, which ensures that the value is treated as a literal (regex metacharacters such as .
are \
-escaped).
and then embed it in a single-quoted string via -f
, the (string) format operator, which allows embedding of RHS operands via indexed placeholders in the LHS format string; e.g., {0}
is the 1st RHS operand, {1}
the 2nd, and so on; use {{
and }}
to escape literal {
and }
.
For example, to construct a regex that matches an arbitrary value $var
if preceded by one ore more digits (\d+
) at a word boundary (\b
) and if positioned at the end of the string ($
)
# The value to embed in the regex, to be interpreted as a *literal*.
$var = '$'
# Embed the escaped value in the regex.
# This results in the following regex - note the \-escaped $
# \b\d+\$$
$regex = '\b\d+{0}$' -f [regex]::Escape($var)
# Perform matching:
'Cost: 20$' -match $regex # -> $true
As for your specific WinForm problem:
.Controls.Find()
on a WinForm form / control only allows searching for controls by their full, literal name, not by a regex.
Therefore you must enumerate all controls recursively and match their .Name
property values individually.
Note that controls aren't required to have names.
Given that there is no built-in way to perform recursive enumeration of the controls contained inside a form / control, you must first implement that yourself, then filter by -match
with a regex:
# Example:
# Get-ChildControl -Recurse $form
function Get-ChildControl {
param([System.Windows.Forms.Control] $Control, [Switch] $Recurse)
foreach ($child in $Control.Controls) {
$child
if ($Recurse) { Get-ChildControl -Recurse:$Recurse $child }
}
}
$regex = '^{0}[A-Z]{1}[a-z]{3}[A-Z]{1}[a-z]{2}.{1}$' -f [regex]::Escape($name)
$TextBoxes = Get-ChildControl -Recurse $NetworkForm | Where { $_.Name -cmatch $regex }
Note the use of -cmatch
to perform case-sensitive matching.
-match
(and its alias -imatch
) are case-insensitive by default, as is PowerShell in general.
As for the problems with your original regex:
Don't use '...'
(literal strings) if you want to embed expressions such as [regex]::escape($name)
in it.
To do so, you must use an expandable string ("..."
) and embed the expression inside $(...)
, not (...)
- as shown in @TobyU's answer.
The alternative is to use -f
, the string-formatting operator, as shown above.
Generally, PowerShell has no regex-literal syntax, it just uses strings, so don't use /.../
inside a string representing a regex.
Upvotes: 1
Reputation: 3908
You can build a string of the pattern before and use it afterwards.
$pattern = "/^($([regex]::escape($name)))[A-Z]{1}[a-z]{3}[A-Z]{1}[a-z]{2}.{1}$/"
$TextBoxes = $NetworkForm.Controls.Find($pattern, 1)
Upvotes: 1