salut,
En powershell on peux remplacer des chaines de caractères par plusieurs manières, nous allons examiner seulement les manières "officielles" qui sont au nombre de trois:
* la methode replace() de la classe 'System.string'
* l'operateur -replace et ses variantes -[ci]?replace
* la methode statique replace() de la classe 'Text.RegularExpressions.Regex'
1) methode replace() de la classe System.string
on peux voir la signature de cette methode en utilisant:
cette methode n'utilise pas de Regex et est case-sensitive
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 ''.replace.overloaddefinition string Replace(char oldChar, char newChar) string Replace(string oldValue, string newValue)
on peux chainer nos traitments pour avoir une unité plus complexe:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 PS > 'developpEz'.replace('e','.') d.v.loppEz
cette methode nous permet d'utiliser les caracteres speciaux, pour plus de détails sur les caractères spéciaux vous pouvez voir l'aide "man about_Special_Characters":
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 PS > 'developpEz'.replace('e','.').replace('E','#') d.v.lopp#z
la chaine à remplacer est litterale, donc on ne soucis plus d'échapper les caractères reservés des Regex:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 PS > 'developpEz'.replace('d',"`td") developpEz
A/ Avantage:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 PS > '$developpez'.replace("$","^") ^developpez
------------
cette méthode est simple, nous permet de manipuler les caractères reservé sans se soucier de les échapper et en plus elle est rapide:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 PS > $s = 'a*' * 100000 PS > (measure-command { $s.replace("*","#") }).TotalMilliseconds 4,745 PS > (measure-command { $s -replace "\*","#" }).TotalMilliseconds 108,828 PS > (measure-command { [regex]::replace($s ,"\*","#") }).TotalMilliseconds 95,09
B/ limites
si on veux faire un remplcement plus complexe, cette méthode ne suffira plus
2) operateur -replace et ses variantes:
Si nous voulons un traitement plus sophistiqué (mais pas trop) on peux utiliser l'operateur -replace, qui permet d'utiliser des Regex
comme vous pouvez le voir, cet operateur n'est pas case sensitive, pour qu'on change se comportement on peux soit utiliser sa variante '-creplace'
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 PS > 'developpEz' -replace 'e','.' d.v.lopp.z
ou bien utiliser le modificateur de case directement dans notre pattern:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 PS > 'developpEz' -creplace 'e','.' d.v.loppEz
l'avantage du modificateur sera clarifier plus tard.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 PS > 'developpEz' -replace '(?-i)e','.' d.v.loppEz
l'operateur -replace peux traiter une chaine comme il peux traiter une liste:
on peux utiliser des references pour nos captures:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 PS > 'ABC','BBA','DFF' -replace 'A','.' .BC BB. DFF
dans notre exemple on a utiliser des references numeriques '\1' et '$1' (remarque: la syntaxe '\1' est utiliser dans la parti du pattern, la syntaxe '$1' est utilisé dans la partie de remplacement) qui sont des copies de la capture '()', sachant que les Regex du moteur .NET nous offre aussi la possibilité d'utiliser des reference nommé \k<hello>:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 PS > 'Ppooooowwweeershhhhhheell' -replace '(.)\1*(?!$)','$1' Powershell
puisque l'operateur -replace utilise les regexp, quelques caractères deviennent spéciales, pour les échapper et les utiliser littéralement on peux: soit les échapper manuellement soit utiliser la fonction statique Escape():
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 PS > 'Ppooooowwweeershhhhhheell' -replace '(?<hello>.)\k<hello>*(?!$)','$1' Powershell
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 PS > '\\\\\' -replace '\','.' Mode d'expression régulière non valide*: \. PS > '\\\\\' -replace [regex]::Escape('\'),'.' .....
A/ Avantage:
------------
cet opérateur supporte les Regex, peux être chainer et est facile d'utilisation
B/ limites
---------------
il ne supporte pas "les expressions lambda" et n'a pas d'options avancées comme est le cas pour la méthode statique de la classe 'Text.RegularExpressions.Regex'
3)a) methode statique replace()
la methode statique replace() de la classe 'Text.RegularExpressions.Regex' est sensible à la case:
si on regarde sa signature:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 PS > [Regex]::replace('DEVeloppez','[a-z]','.') DEV.......
on constate qu'elle nous offre plusieurs autre possibilitées, on peux utiliser des options plus avancées pour notre regex:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8 [regex]::Replace.OverloadDefinitions static string Replace(string input, string pattern, string replacement) static string Replace(string input, string pattern, string replacement, System.Text.RegularExpressions.RegexOptions options) static string Replace(string input, string pattern, System.Text.RegularExpressions.MatchEvaluator evaluator) static string Replace(string input, string pattern, System.Text.RegularExpressions.MatchEvaluator evaluator, System.Text.RegularExpressions.RegexOptions options)
quelques options ont leurs propres modificateurs comme:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 PS > [enum]::getnames([Text.RegularExpressions.RegexOptions]) None IgnoreCase Multiline ExplicitCapture Compiled Singleline IgnorePatternWhitespace RightToLeft ECMAScript
on peux aussi combiner entre les options en les séparant par une virgule:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 (?x) IgnorePatternWhitespace (?i) IgnoreCase (?s) Singleline (?m) Multiline
dans ce regex on peux voir que le modificateur '(?-i)' prend le dessus sur l'option 'ignorecase', on pourra uiliser plusieurs modificateurs dans une même expression.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 PS > $pat = @' >> ^ # le debut de la ligne >> .{3} # n'importe quel caractère (trois fois) >> (?-i) # respecter la casse pour ce bloc >> (?! # tester la partie suivante pour voir s'il n' y a pas >> E # caractère litteral 'e' >> ) # fermeture du groupe de negation non-capturant >>'@ >> PS > [Regex]::replace( >> 'DEVeloppez', >> $pat, >> '###', >> 'ignorecase,IgnorePatternWhitespace' >> ) >> ###eloppez
on peux aussi créer une "expression lambda" qu'on passe comme un scriptblock
cette technique est comparable a celle-ci :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13 PS > $s = 'ceci est un simple exemple' PS > [regex]::replace( >> $s, >> '\b\w+\b', >> { >> param($word) >> $len = $word.length >> '{1}({0})' -f $len,$word >> } >> ) >> ceci(4) est(3) un(2) simple(6) exemple(7)
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 PS > {param($s) $s * $s}.invoke(9) 81
3)b) caster une chaine de caractères/et ou variable en [regex]:
une autre methode est de caster une chaine de caractere
ou bien caster une variable:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 $re = [regex]'kb\d+'
la difference entre les deux cast est que la premiere affecte uniquement la valeur de la variable tandis que la derniere affecte la variable elle même:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 [regex]$re = 'kb\d+'
si on observe la signature de cette variante:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 PS > $re = [regex]'kb\d+' PS > $re.GetType().fullname System.Text.RegularExpressions.Regex PS > $re = 1 PS > $re.GetType().fullname System.Int32 PS > [regex]$re = 'kb\d+' PS > $re.GetType().fullname System.Text.RegularExpressions.Regex PS > $re =ls Impossible de convertir la valeur «*System.Object[]*» du type «*System.Object[]*» en type «*System.Text.RegularExpressions.Regex*»
nous pouvons voir qu'il y a deux nouvelles options 'count' et 'startat' qui sont de type 'int', l'argument 'count' est le nombre de match que le regex doit matcher, l'argument 'startat' est la position du match reussi.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 $regex = [regex]'h' $regex.Replace.OverloadDefinitions string Replace(string input, string replacement) string Replace(string input, string replacement, int count) string Replace(string input, string replacement, int count, int startat) string Replace(string input, System.Text.RegularExpressions.MatchEvaluator evaluator) string Replace(string input, System.Text.RegularExpressions.MatchEvaluator evaluator, int count) string Replace(string input, System.Text.RegularExpressions.MatchEvaluator evaluator, int count, int startat)
A/ Avantage:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 PS > $regex = [regex]'\d' PS > $text = '0123456789' PS > $regex.Replace($text,'#') ########## PS > $regex.Replace($text,'#',1) #123456789 PS > $regex.Replace($text,'#',3,4) 0123###789 PS > $regex.Replace($text, >> '#', >> -1, >> <# >> '-1' toute la chaine >> ou bien: $text.length >> #> >> 4) >> 0123######
elle permet d'utiliser toute la puissance des Regex .NET avec ses options avancées et les expressions-lambda
B/ limites
les expressions lambda peuvent aider enormement mais peuvent aussi rendre nos codes cryptic.
cette méthode n'est pas aussi flexible que l'opérateur -replace
dans cette brief explication j'ai essayé de m'eloigner le plus possible des Regex pour que l'explication ne devienne un tutoriel sur les Regex plutot qu'un tutoriel sur les méthodes 'officiels' de remplacement et la difference entre chaqu'une d'elle, mais après avoir relu ce petit how-to , je me suis apercu que separer entre les Regex et le but de ce petit tutoriel est plus difficile pour moi que je ne l'imagineais
toute autre contribution/critique est la bien venu.
Partager