Eu tenho uma instrução switch que é bastante longa (mais de 120 códigos) e é uma correspondência de string simples para onde uma determinada string/código fará com que um determinado conjunto de comandos seja executado (portanto, não há necessidade de regex). Mas, enquanto pensava nisso, ocorreu-me que gostaria de passar os nomes de usuário pelo mesmo switch para realizar a mesma tarefa para cada usuário, usando seu nome de usuário.
Tentei fazer isso colocando -match
dentro da condição com um regex de grupo de captura nomeado para obter o nome de usuário, mas falhou:
$code1 = 'Descriptive text describing code 1'
$code2 = 'Descriptive text describing code 2'
$userName1 = 'user_UserName1'
$userName2 = 'user_UserName2'
$Codes = $code1, $code2, $userName1, $userName2
switch ($Codes) {
$code1 {
Write-Host 'Do work required by code1'
continue
}
$code2 {
Write-Host 'Do work required by code2'
continue
}
{$_ -match '^user_(?<UserName>.*)$'} {
Write-Host ('Processing user: {0}' -f $Matches.UserName)
continue
}
default {'Other'}
}
Resultados com falha:
Do work required by code1
Do work required by code2
Processing user:
Processing user:
Onde eu esperava isso:
Do work required by code1
Do work required by code2
Processing user: UserName1
Processing user: UserName2
E embora o seguinte funcione, como você pode ver, estou tendo que executar -match
duas vezes:
$Codes = 'user_UserName1', 'user_UserName2'
switch ($Codes) {
{$_ -match '^user_(?<UserName>.*)$'} {
if($_ -match '^user_(?<UserName>.*)$') {
Write-Host ('Processing user: {0}' -f $Matches.UserName)
}
continue
}
default {'Other'}
}
Suponho que a condição seja um bloco de script executado em seu próprio escopo e $Matches
não esteja disponível fora desse escopo. Não consigo return $userName
entrar no bloco de script, pois tenho certeza de que é assim que o valor $true
/ $false
é recebido pelo switch.
Existe um método simples para evitar a correspondência uma vez para troca e novamente para $Matches
disponibilização?
Código Final Baseado na resposta e comentários de Santiago:
Não estou animado por ter que adicionar [regex]::Escape(
na frente de cada string de descrição de código e um final )
, mas isso mantém o texto legível e torna as variáveis regex seguras:
$code1 = [regex]::Escape('Descriptive text (with special characters) describing code 1.')
$code2 = [regex]::Escape('Descriptive text (with special characters) describing code 2.')
Esta parte permanece a mesma:
$userName1 = 'user_UserName1'
$userName2 = 'user_UserName2'
$Codes = $code1, $code2, $userName1, $userName2
Os códigos $Codes
precisam ser de texto simples, portanto, a próxima linha remove os escapes de regex, a instrução switch agora usa o -regex
switch e a condição para capturar códigos de usuário é reduzida a uma string contendo o regex para capturar o nome de usuário.
$Codes = $Codes | & {process{[regex]::Unescape($_)}}
switch -Regex ($Codes) {
$code1 {
Write-Host 'Do work required by code1'
continue
}
$code2 {
Write-Host 'Do work required by code2'
continue
}
'^user_(?<UserName>.*)$' {
Write-Host ('Processing user: {0}' -f $Matches.UserName)
continue
}
default {'Other'}
}
Uma solução ligeiramente alterada
Esta é uma melhoria na solução acima, estendendo objetos do tipo string para incluir as propriedades .reEscape
e .reUnescape
. Isso é feito através da seguinte classe:
class MyExtensions {
static [string]reEscape([PSObject]$source) { return [regex]::Escape($source) }
static [string]reUnescape([PSObject]$source) { return [regex]::Unescape($source) }
static [void]AddTypeProperty([string]$typeName, [string]$MemberName) {
Update-TypeData -TypeName $typeName -MemberName $MemberName -MemberType CodeProperty -Value ([MyExtensions].GetMethod($MemberName)) -Force
}
static [void]Initialize() {
[MyExtensions]::AddTypeProperty('System.String', 'reEscape')
[MyExtensions]::AddTypeProperty('System.String', 'reUnescape')
}
}
Colocada a linha a seguir perto do topo do código, ela faz o trabalho real de adicionar as propriedades aos objetos do tipo string.
[MyExtensions]::Initialize()
Removido [regex]::Escape(
das seguintes linhas e adicionado .reEscape
no final.
$code1 = 'Descriptive text (with special characters) describing code 1.'.reEscape
$code2 = 'Descriptive text (with special characters) describing code 2.'.reEscape
E a remoção dos escapes agora pode ser feita desta forma:
$Codes = $Codes | & {process{$_.reUnescape}}