Question
regex - iteration mulitple dans une chaine
- Marc
- Auteur du sujet
- Hors Ligne
- Membre premium
-
- Messages : 90
- Remerciements reçus 0
je m'essais aux regex
chaine:
[code:1]'tcp://10.10.10.10-10.10.10.20:443,80,1025,856,58880[/code:1]
Je souhaite dissocier les IP.
[code:1]$a = 'tcp://10.10.10.10-10.10.10.20:443,80,1025,856,58880'
$IP = '(?<IPS>(?<IP1>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})-?(?<IP2>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})|(?<IP>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}))'
$a -match $IP
$Matches[/code:1]
Ca marche, mais je trouve ça vraiment très moche.
J'ai beau chercher sous powershell les seul commutateurs utilisables que j'ai trouvé sont:
[code:1]-match
-replace[/code:1]
Existe-t-il un moyens de faire quelque chose qui ressemble à ça ?
[code:1]$IP = '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'
foreach($x in $a -like $IP){write-host $x}[/code:1]
Ou alors ma première regex est mal construite ?
Parce que après les IP je doit extraire les ports
J'ai bien un script qui me résout ça avec des split, substring et consort, mais je souhaite vraiment me frotter aux regex.
Connexion ou Créer un compte pour participer à la conversation.
- Laurent Dardenne
- Hors Ligne
- Modérateur
-
- Messages : 6311
- Remerciements reçus 68
ça se discuteCa marche, mais je trouve ça vraiment très moche.
marcci écrit:
[code:1]foreach($x in [regex]::Matches($A,$IP))Existe-t-il un moyens de faire quelque chose qui ressemble à ça ?
{write-Warning $x; $x|select *}[/code:1]
marcci écrit:
Non, on peut faire mieux je pense.Ou alors ma première regex est mal construite ?
L'avantage est qu'un débutant en regex peut la relire.
marcci écrit:
Dans cas la syntaxe précédente n'est peut être plus adaptée, faut tester.Parce que après les IP je doit extraire les ports
Dans ton exemple tu recherches 0 ou n occurrences d'une information de même structure, le port en est une autre. On doit donc pouvoir les dissocier, l'usage de capture nommée est une piste.
Regarde aussi le cmdlet ConvertFrom-String
Tutoriels PowerShell
Connexion ou Créer un compte pour participer à la conversation.
- Marc
- Auteur du sujet
- Hors Ligne
- Membre premium
-
- Messages : 90
- Remerciements reçus 0
on est jamais déçus en postant ici
Ce que je retient, c'est la class [regex]
Ainsi tout deviens très simple
[code:1]$ChaineAtraiter = 'tcp://10.10.10.10-10.10.10.20:443,80,1025,856,58880'
$regexIP = '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'
$regexPORT = '((?::«»)\d{1,})|((?:,)\d{1,})'
$IPs = [Regex]::Matches($ChaineAtraiter,$regexIP)
$Ports = [Regex]::Matches($ChaineAtraiter,$regexPORT)
$Ips.value
$Ports.value|foreach{$_.remove(0,1)}[/code:1]
Quand on résout un problème un autre ce la ramène sans attendre
Je n'arrive pas à sortir les ':' et ',' de la capture en utilisant '(?:
J'ai peut-être mal compris l'utilisation de '(?:exp)'.
Connexion ou Créer un compte pour participer à la conversation.
- Laurent Dardenne
- Hors Ligne
- Modérateur
-
- Messages : 6311
- Remerciements reçus 68
De ce que j'ai compris, selon MSDN :J'ai peut-être mal compris l'utilisation de '(?:exp)'.
Les parenthèses externes de cette expression définissent celle-ci en tant que groupe de capture ou que sous-expression.
Si une correspondance est trouvée, les informations sur cette partie de la chaîne correspondante peuvent être récupérées du deuxième objet Group dans
l'objet GroupCollection retourné par la propriété Match.Groups. (Le premier élément de la collection représente la correspondance entière.)
Voyons ça :
[code:1]
\"Writeline(value)\" -match 'WriteLine'
#True
$matches
# Name Value
# ----
# 0 Writeline
[/code:1]
Ok ça matches, mais pas de capture.
Mnt une capture avec un groupement :
[code:1]
\"Writeline(value)\" -match 'Write(Line)'
#True
$matches
# Name Value
# ----
# 1 line
# 0 Writeline
[/code:1]
Le group 1 contient la capture.
Mnt on ne veut pas capturer le groupe défini :
[code:1]
\"Writeline(value)\" -match 'Write(?:Line)'
#True
$matches
# Name Value
# ----
# 0 Writeline
[/code:1]
Ok, identique à un match simple (pas de group 1)
Mnt une capture constituée de 2 groupes dont l'un est déclaré comme ne devant pas être capturé :
[code:1]
\"Writeline(value)\" -match '(Write(?:Line))'
#True
$matches
# Name Value
# ----
# 1 Writeline
# 0 Writeline
[/code:1]
L'occurence trouvée contient tout les groupes, mais 'line' en tant que groupe n'est pas précisé, sa prise en compte se déclarant ainsi : '(Write(Line))'
Donc selon la construction, une demande de ne pas capturer un groupe ne l'exclu pas de la reconnaissance.
C'est ce qui se passe avec $regexPORT = '((?:
On peut déclarer un second groupe sur le numéro du port :
[code:1]
$ChaineAtraiter -match '(?::«»)(\d{1,})|(?:,)(\d{1,})'
$matches
# Name Value
# ----
# 1 443
# 0 :443
[/code:1]
Avec la classe [regex] il faut aller chercher le group 1 et pas le group 0 ($Port.Value)
[code:1]
$regexPORT = '(?::|,)(\d{1,})'
$Ports = [Regex]::Matches($ChaineAtraiter,$regexPORT)
$Ports|% {$_.groups[1].value}
# 443
# 80
# 1025
# 856
# 58880
[/code:1]
Et concernant le code ne j'aurais fait qu'une analyse avec une seule regex
Tutoriels PowerShell
Connexion ou Créer un compte pour participer à la conversation.
- Marc
- Auteur du sujet
- Hors Ligne
- Membre premium
-
- Messages : 90
- Remerciements reçus 0
Et concernant le code ne j'aurais fait qu'une analyse avec une seule regex
Oui moi aussi mais je n'y arrive pas, ces petites bêtes sont pour le moins mystérieuse leur comportement met les nerfs à vif.
Du coup je fais autant de passe que de format de data possible en input, heureusement sur ce cas il ne peut pas y en avoir 36.
Mais je n'abandonne pas, les regex sont LA solution pour les users qui aiment faire avaler n'importe quoi aux script
[code:1]
function RetrieveData {
param($ACLsData)
[psobject]$ACLs = @()
foreach($line in $ACLsData)
{
$IPs = [Regex]::Matches($line,'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}')
$PortVirgule = [regex]::Matches($line,'(?::|,)(\d{1,})')
$PortTiret = [regex]::Matches($line,'(?::|,)(\d{1,}-\d{1,})')
if($PortTiret.count)
{
$allPorts = $PortTiret.groups[1].value
}
else{
$allPorts = $PortVirgule|foreach{$_.groups[1].value}
}
$IP = $Ips.value
if($IP.count -gt 1)
{
$IP = $IP[0]+\"-\"+[regex]::Replace($IP[1],'\d{1,3}\.\d{1,3}\.\d{1,3}\.',\"\"«»)
}
foreach($Port in $allPorts)
{
$ACLs += New-Object psobject -Property @{
'IP' = $IP
'Port' = $Port
}
}
}
return $ACLs
}
$Chainepossible =@'
tcp://10.10.10.10-10.10.10.20:1000-1024
tcp://10.10.10.10-10.10.10.20:443,80,1080
tcp://10.10.10.10:1000-1024
tcp://10.10.10.10:443,80,1080'
'@
RetrieveData $Chainepossible.split(\"`n\"«») | ft -AutoSize
IP Port
-- ----
10.10.10.10-20 1000-1024
10.10.10.10-20 443
10.10.10.10-20 80
10.10.10.10-20 1080
10.10.10.10 1000-1024
10.10.10.10 443
10.10.10.10 80
10.10.10.10 1080
[/code:1]
Connexion ou Créer un compte pour participer à la conversation.
- Laurent Dardenne
- Hors Ligne
- Modérateur
-
- Messages : 6311
- Remerciements reçus 68
Oui c'est souvent énervantOui moi aussi mais je n'y arrive pas, ces petites bêtes sont pour le moins mystérieuse leur comportement met les nerfs à vif.
Il faut déjà avoir un jeu de test qui couvre TOUT les cas ou les plus récurrent quitte à indiquer que certaines lignes ne correspondent pas.
Ensuite la rédaction de spécification claire aide à l'écriture de regex.
Selon Jeffrey E.F.Friedl, l'apprentisage des regex se fait sur la durée, au début la progression est rapide ensuite on stagne avant d'aller de l'avant.
Tutoriels PowerShell
Connexion ou Créer un compte pour participer à la conversation.
- Vous êtes ici :
-
Accueil
-
forum
-
PowerShell
-
Entraide pour les débutants
- regex - iteration mulitple dans une chaine