regexpowershellreplacetextboxtextchanged

PowerShell WinForms textbox, prevent unwanted regex pattern characters


In PowerShell I've been trying different ways of stripping out all characters from a WinForms textbox other than the pattern I need and I cannot come up with a better solution for what I'm after; I am learning regex and need some guidance. This feels basic to me but I feel like I'm missing something obvious. I'm using the textbox's TextChanged event to prevent illegal characters from being typed and I have (what feels like) a bloated solution.

Goal:


Pasting into the textbox examples:


Things I've tried so far:

This is the mostly working solution I have thus far in the textbox's TextChanged event:

Clear-Host
Add-Type -AssemblyName System.Windows.Forms

$btnExit = New-Object System.Windows.Forms.Button -Property @{
    Location        = '50, 100'
    Text            = 'E&xit'
}

$frmTestForm = New-Object System.Windows.Forms.Form -Property @{
    CancelButton    = $btnExit
    FormBorderStyle = 'Fixed3D'
    MaximizeBox     = $false
}

$txtTextbox = New-Object System.Windows.Forms.TextBox -Property @{
    Location        = '50, 50'
    CharacterCasing = 'Upper'
}

$frmTestForm.Controls.Add($btnExit)
$frmTestForm.Controls.Add($txtTextbox)

$txtTextbox.Add_TextChanged({

    $TempString = $txtTextbox.Text
    foreach ($Character in $txtTextbox.Text.ToCharArray() )
    {
        # Working, but doesn't allow user to type a '$'
        if (! ([regex]::IsMatch($Character, '^[A-V0-9]$' ) ))
        {
            $TempString = $TempString.Replace([string]$Character, "")
        }
    }
    if ($TempString.Length -ne 0 -and $TempString[0] -ne '$')
    {
        # Add a leading '$' if there isn't one
        $txtTextbox.Text = '$' + $TempString.Substring(0, [System.Math]::Min(6, $TempString.Length))

    }
    elseif ($txtTextbox.Text -eq '$')
    {
        # Deletes the $ automatically once the last remaining (legal) character is deleted.
        # This also unfortunately prevents the user from manually typing a leading '$'
        $txtTextbox.Clear()
    }
    else
    {
        # Prevent leading illegal characters from showing up/producing '$' and nothing else
        $txtTextbox.Text = ''
    }
    
    $txtTextbox.Select($txtTextbox.Text.Length, 0)
})

$btnExit.Add_Click({
    $frmTestForm.Close()
})

$frmTestForm.Add_Shown({
    $txtTextbox.Select()
})

[System.Windows.Forms.Application]::Run($frmTestForm)

It doesn't allow the user to manually type in a $ as noted in the comments, but that might be something I'm willing to give up if allowing this would introduce a lot more bloat. At the end of the day, my question is simply:


Would a regex that's along the lines of:
$txtTextbox.Text = $txtTextbox.Text -replace 'everything that isn't a leading $ in addition to [^A-V0-9]{0,6}' be simpler/faster/more efficient compared to evaluating each character one at a time? What would that regex look like?

Thank you in advance for any insight or (hopefully constructive) criticism.

-Paul


Solution

  • Using your test strings , I came up with this:

    $txtTextbox.Add_TextChanged({
        $TempString = $this.Text
        if ($TempString -ne '$') { 
            $TempString = ($this.Text).TrimStart('$') -replace '[^A-V0-9]'
            if ($TempString.Length -gt 6) { $this.Text = '${0}' -f $TempString.Substring(0,6) }
            elseif ($TempString.Length) { $this.Text = '${0}' -f $TempString }
            else { $this.Clear() }
        }
        elseif ($this.Tag -eq 2) { 
            # user backspaced the last character before the '$'
            $this.Clear()
        } 
    
        $this.Tag = $this.Text.Length       # keep track of the current text length
        $this.Select($this.Text.Length, 0)  # set the cursor to the end
    })