Question regex - iteration mulitple dans une chaine

Plus d'informations
il y a 9 ans 2 semaines #23240 par Marc
Bonjour a tous.
je m'essais aux regex :unsure:

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 :pinch:

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.

Plus d'informations
il y a 9 ans 2 semaines #23241 par Laurent Dardenne
marcci écrit:

Ca marche, mais je trouve ça vraiment très moche.

ça se discute :-)
marcci écrit:

Existe-t-il un moyens de faire quelque chose qui ressemble à ça ?

[code:1]foreach($x in [regex]::Matches($A,$IP))
{write-Warning $x; $x|select *}[/code:1]
marcci écrit:

Ou alors ma première regex est mal construite ?

Non, on peut faire mieux je pense.
L'avantage est qu'un débutant en regex peut la relire.
marcci écrit:

Parce que après les IP je doit extraire les ports

Dans cas la syntaxe précédente n'est peut être plus adaptée, faut tester.
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.

Plus d'informations
il y a 9 ans 2 semaines #23242 par Marc
Bonjour,

on est jamais déçus en postant ici B)

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 :pinch:

Je n'arrive pas à sortir les ':' et ',' de la capture en utilisant '(?::)' et '(?:,)' et suis obligé de mettre un .remove
J'ai peut-être mal compris l'utilisation de '(?:exp)'.

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
il y a 9 ans 2 semaines #23244 par Laurent Dardenne
marcci écrit:

J'ai peut-être mal compris l'utilisation de '(?:exp)'.

De ce que j'ai compris, selon MSDN :

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 = '((?::)\d{1,})|((?:,)\d{1,})'
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.

Plus d'informations
il y a 9 ans 2 semaines #23247 par Marc
Bonjour,

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.

Plus d'informations
il y a 9 ans 2 semaines #23248 par Laurent Dardenne
marcci écrit:

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.

Oui c'est souvent énervant :-), quand aux mystères il faut être patient pour comprendre les comportements.

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.

Temps de génération de la page : 0.059 secondes
Propulsé par Kunena