Question [Function PS v2] Replace-String
- Laurent Dardenne
- Auteur du sujet
- Hors Ligne
- Modérateur
- Messages : 6302
- Remerciements reçus 68
Salut,
je vous propose une fonction avancée permettant une opération de cherche/remplace.
Elle dispose d'une aide intégrée (Replace-String -?) contenant de nombreux exemples (13).
Son principe se base sur les méthodes de remplacement String.Replace() ou sur Regex.Replace() (par défaut).
Le paramètrage se fait via une hastable respectant un format 'normalisé'.
Cette fonction permet :
-des remplacements multiples sur une même chaîne de caractères,
-des remplacements multiples sur des propriétés d'objets (les jokers sont supportés),
-d'exécuter une seule opération de recherche et de remplacement parmis une liste (la première qui réussit),
-de récupérer la valeur de la chaîne de remplacement à partir d'un scriptblock,
-de remplacer 1, plusieurs ou toutes les occurences trouvées,
-de débuter la recherche à une position donnée, par exemple à partir du 10 caractères,
-de préciser des options sur les regex [System.Text.RegularExpressions.RegexOptions],
-de récupérer le résultat d'exécution de chaque regex dans un objet personnalisé,
-d'utiliser des conversions de tableaux basée sur la variable $OFS,
-de générer des fichiers ou du code à partir de templates,
-de combiner l'ensemble de ces possibilités.
Voici quelques exemples, je vous laisse lire le détail dans la documentation.
Remplacement multiple dans une chaîne à l'aide d'expression régulière :
[code:1]
$S= \"Caractères : 33 \d\d\"
$h=@{}
$h.\"a\"=\"?\" # regex 1
$h.\"\d\"='X' # regex 2
Replace-String -i $s $h
#Voir le résultat dans la doc
[/code:1]
Remplacement multiple dans une chaîne, on utilise un délégué (MatchEvaluator):
[code:1]
$S= \"Caractères : 33\"
$h=@{}
$h.\"a\"=\"?\" # regex 1
$h.\"(?<Chiffre>\d)\"='${Chiffre}X' # regex 2
$h.\":\"={ Write-Warning \"Call delegate\"; return \"<$($args[0])>\"} # regex 3
$S|Replace-String $h
[/code:1]
Remplacement multiple dans une chaîne, on paramètre l'expression régulière :
[code:1]
$S= \"CAractères : 33\"
$h=@{}
$h.\"a\"=@{Replace=\"?\";StartAt=3;Options=\"IgnoreCase\"} #hastable normalisée.
#La recherche débute à partir du 3ième caractéres
$h.\"\d\"=@{Replace='X';Max=1} #Un seul remplacement
$S|Replace-String $h
[/code:1]
On récupère dans une variable une liste d'objets personnalisés détaillant les opérations :
[code:1]
$O=New-Object PSObject -Property @{Name=\"Test_ToDelete.tmp\";Path=\"C:\Temp\";Value=\"Fichier de tests.\";Type=\"File\"}
$G=New-Object PSObject -Property @{Name=\"TestRpls.ps1\";Path=\"D:\PS\Tests\";Value=\"Test-Object\";Type=\"File\"}
\"Test Replace-String -Property\"|Set-Content \"C:\Temp\Test_Replace-String-Property.txt\" -Force
$F=dir \"C:\Temp\Test_Replace-String-Property.txt\"
#On convertis les objets en [String]
#Les objets ne sont pas modifiés
$Result=$O,$G,$F|rpls @{\"Test\"=\"New\"} -ReplaceInfo
$Result[0]|fl
$Result|% {$_.Replaces|fl}
[/code:1]
Remplacement multiple de propriétés d'objets ( de type [string] en R/W), pour chaque objet reçu on effectue un seul traitement parmis plusieurs:
[code:1]
$AllObjects=dir Variable:
$AllObjects| Ft Name,Description|More
$h=@{}
$h.\"^$\"={\"Nouvelle description de la variable $($InputObject.Name)\"}
#PowerShell V2 FR
$h.\"(^Nombre|^Indique|^Entraîne)(.*)$\"='POWERSHELL $1$2'
#Les objets sont modifiés
$Result=$AllObjects|Replace-String $h -property \"Description\" -ReplaceInfo -Unique
$AllObjects| Ft Name,Description|More
[/code:1]
Remplacement multiple dans des fichiers :
[code:1]
#Paramètrage
$NumberVersion=\"1.2.1\"
$Version=\"# Version : $Numberversion\"
#La date est substituée une seule fois lors
#de la création de la hashtable.
$Modifications= @{
\"^\s*\#\s*Version\s*:«»(.*)$\"=$Version;
'^\s*\#\s*Date\s*:«»(.*)$'=\"# Date : $(Get-Date -format 'd MMMM yyyy')\"
}
$RunWinMerge=$False
#Fichiers de test :
# projets.developpez.com/projects/add-lib/files
cd \"G:\PS\Replace-String\TestReplace\"
#Cherche et remplace dans tous les fichiers .ps1 d'une arborescence, sauf les .bak
#Chaque fichier est recopié en .bak avant les modifications
Get-ChildItem *.ps1 -exclude *.bak -recurse|
Where-Object {!$_.PSIsContainer} |
ForEach-Object {
$CurrentFile=$_
$BackupFile=\"$($CurrentFile).bak\"
Copy-Item $CurrentFile $BackupFile
Get-Content $BackupFile|
Replace-String $Modifications|
#binding automatique
Set-Content -path $CurrentFile
#compare le résultat à l'aide de Winmerge
if ($RunWinMerge)
{Microsoft.PowerShell.Management\start-process \"C:\Program Files\WinMerge\WinMergeU.exe\" -Argument \"/maximize /e /s /u $BackupFile $CurrentFile\" -wait}
} #foreach
[/code:1]
Remplacement multiple basé sur une alternative, construite à partir d'un tableau de chaîne, couplée à un scriptblock :
[code:1]
$S=\"Un petit deux-roues, c'est trois fois rien.\"
$Alternatives=@(\"un\",\"deux\",\"trois\"«»)
#En regex '|' est le métacaractère
#pour les alternatives.
$ofs=\"|\"
$h=@{}
$h.$Alternatives={
switch ($args[0].Groups[0].Value) {
\"un\" {\"1\"; break}
\"deux\" {\"2\"; break}
\"trois\" {\"3\"; break}
}#switch
}#$s
$S|Replace-String $h
$ofs=\"\"
[/code:1]
Il est possible d'utiliser la librairie de regex du projet PSCX :
[code:1]
\"un deux deux trois\"|Replace-String @{$PSCX:RegexLib.RepeatedWord=\"Deux\"}
#renvoi
#un deux trois
[/code:1]
Le fichier joint contient le script de la fonction et un fichier de tests à compléter.
La fonction supporte le paramètre -Whatif, génére des erreurs non bloquante catégorisées et contient des traces pour le debug.
La pièce jointe Replace_String.zip est absente ou indisponible
Tutoriels PowerShell
Pièces jointes :
Connexion ou Créer un compte pour participer à la conversation.
- Richard Lazaro
- Hors Ligne
- Membre platinium
- Messages : 530
- Remerciements reçus 0
Ben bravo, une grosse doc, lisible comme j'aime :]
Après, pourquoi n'utilises-tu pas la variable $PSCmdlet ?
Et puis j'aime pas trop les return de partout comme je te l'avais déjà dis ... mais j'ai une vision d'une programmation C#. Peut être qu'en PowerShell c'est admis d'avoir des return de partout.
Think-MS : (Get-Life).Days | %{ Learn-More }
\\"Problems cannot be solved by the same level of thinking that created them.\\" - Albert Einstein
Connexion ou Créer un compte pour participer à la conversation.
- Richard Lazaro
- Hors Ligne
- Membre platinium
- Messages : 530
- Remerciements reçus 0
Think-MS : (Get-Life).Days | %{ Learn-More }
\\"Problems cannot be solved by the same level of thinking that created them.\\" - Albert Einstein
Connexion ou Créer un compte pour participer à la conversation.
- Laurent Dardenne
- Auteur du sujet
- Hors Ligne
- Modérateur
- Messages : 6302
- Remerciements reçus 68
Richard Lazaro écrit:
Merci pour ton retour.Ben bravo, une grosse doc, lisible comme j'aime :]
J'essaie d'être cohérent, si parfois je critique le manque de documentation sur Powershell, je m'efforce de ne pas faire pareil
Richard Lazaro écrit:
Dans quel contexte ? As-tu un exemple ?Après, pourquoi n'utilises-tu pas la variable $PSCmdlet ?
Richard Lazaro écrit:
Effectivement, une seule fonction en fait un usage prononcé.Et puis j'aime pas trop les return de partout comme je te l'avais déjà dis ...
Ayant fait il y a pas mal de temps de l'assembleur, les différentes approches sont compilées en un simple saut (JMP ).
Je te l'accorde ce n'est pas académique, plutôt pragmatique, d'une part pour la relecture et le debuggage, d'autre part c'est un code \"boule de neige\".Je suis parti d'un script de 4-5 lignes pour un besoin précis, et au fur et à mesure j'ai ajouté des fonctionnalites en ayant à l'esprit de disposer d'un outil aussi riche et puissant que l'opérateur -Split disponible sous la V2 (voir about_split.help.txt).
L'équipe de PowerShell n'a pas étendue cette conception pour l'opérateur -Replace, c'est dommage.
Pour en revenir à l'usage des return, cela reflète sûrement un codage sans spécicifations détaillées, une réécriture s'impose donc. Mais avant, je vais déjà voir ce qu'il donne en l'état.
Richard Lazaro écrit:
J'ai conscience que de prime abord cette fonction est difficile à saisir, pourtant il n'y a que 6 paramètres dont 3 switch (Le code peut peut-être l'être).Apres, c'est à tester, car l'utilisation à l'air bien compliqué.
Par défaut on traite des [string] et on renvoi des [string].
Si on précise -Property ont traite des objets et on renvoi des objets.
Enfin si on précise -Replaceinfo on encapsule soit la string soit l'objet dans un objet personnalisé.
Ce dernier permet, comme on autorise plusieurs opérations de remplacement sur une même instance, de récupérer l'instance finale et le résultat (vrai/faux) de l'opération de remplacement.
Le problème est vraisemblablement dans l'usage du paramètre -Hashtable (Hashtable imbriquées).
Comme Replace-String propose des remplacements multiples, je n'ai pas trouvé d'autre approche permettant de regrouper toutes les informations de paramètrage de la méthode suivante :.
[code:1] Regex.Replace (String, MatchEvaluator, Int32, Int32)[/code:1]
La difficulté est peut être aussi dans les nombreuses combinaisons et comportements liés aux trois Switch.
J'ai peut-être pêché par gourmandise
Tutoriels PowerShell
Connexion ou Créer un compte pour participer à la conversation.
- Richard Lazaro
- Hors Ligne
- Membre platinium
- Messages : 530
- Remerciements reçus 0
Je te parle de la variable $PsCmdlet pour le retour de donnée avec la méthode WriteObject, l'écriture de verbose avec la méthode WriteVerbose, etc ...
WriteError
ThrowterminatingError
WriteDebug
Think-MS : (Get-Life).Days | %{ Learn-More }
\\"Problems cannot be solved by the same level of thinking that created them.\\" - Albert Einstein
Connexion ou Créer un compte pour participer à la conversation.
- Laurent Dardenne
- Auteur du sujet
- Hors Ligne
- Modérateur
- Messages : 6302
- Remerciements reçus 68
Question d'habitude je pense, pour celle-ci on avait vu qu'elle n'émettait pas les membres personnalisés.Je te parle de la variable $PsCmdlet pour le retour de donnée avec la méthode WriteObject
Je vais tester un peu plus en profondeur.
Richard Lazaro écrit:
Idem bien que j'utilise déjà Write-Error, ici aussi je vais regarder ce que ça donne. En passant le comportement du paramétre -WarningAction est bugé, voir MSConnect., l'écriture de verbose avec la méthode WriteVerbose, etc ...
WriteError
ThrowterminatingError
WriteDebug
Tutoriels PowerShell
Connexion ou Créer un compte pour participer à la conversation.
- Vous êtes ici :
- Accueil
- forum
- PowerShell
- Contributions à la communauté
- [Function PS v2] Replace-String