Question [Concours Scripting] compare-textfile (validé)

Plus d'informations
il y a 18 ans 5 mois #1195 par Jacques Barathon
Voici un script en réponse au problème posé il y a peu sur le forum concernant la comparaison de deux fichiers texte:

[code:1]
# compare-textfile.ps1
# Auteur: janel
# Date: 18/10/2007
#
# Usage: compare-textfile -reference file1.txt -difference file2.txt
#

param (
$reference,
$difference
)

$file1 = [System.IO.File]::OpenText((dir $reference))
$file2 = [System.IO.File]::OpenText((dir $difference))

$line = 1

while (!$file1.EndOfStream -or !$file2.EndOfStream)
{
$line1 = $line2 = \"\"
($file1.EndOfStream) -or ($line1 = $file1.ReadLine()) > $nul
($file2.EndOfStream) -or ($line2 = $file2.ReadLine()) > $nul

$length = $line1.length
if ($line2.length -gt $length) { $length = $line2.length }

$matchline = New-Object PSObject
$chararray = @()
$diff = 0

for ($i=0;$i -lt $length;$i++) {
if ([char]$line1[$i] -ne [char]$line2[$i]) {
$diffchars = New-Object PSObject
$diffchars | Add-Member -MemberType NoteProperty Position $i
$diffchars | add-member -MemberType NoteProperty Reference $line1[$i]
$diffchars | add-member -MemberType NoteProperty Difference $line2[$i]
$chararray += $diffchars
$diff++
}
}
$matchline | Add-Member -MemberType NoteProperty Line $line
$matchline | Add-Member -MemberType NoteProperty Different $diff
$matchline | Add-Member -MemberType NoteProperty Equal ($length - $diff)
$matchline | Add-Member -MemberType NoteProperty Characters $chararray
$matchline

$line++
}

$file1.Close()
$file2.Close()
[/code:1]
Et en avant-première mondiale :) le commentaire que je m'apprête à poster sur mon blog pour expliquer comment se servir de ce script:

Voici comment s’en servir – imaginons deux fichiers texte simples :

[code:1]
PS> type ref.txt
HELLO WORLD
HOULA HOUP

PS> type dif.txt
HELLO WORLD!
HOULA, HOUPS...[/code:1]
Comme vous le pouvez le voir, dif.txt est une copie de ref.txt auquel quelques modifications ont été apportées : un point d’exclamation a été ajouté à la fin de la première ligne, et sur la deuxième ligne j’ai introduit une virgule entre les deux mots et ajouté un ‘S’ et des points de suspension à la fin.

Maintenant, voyons ce que donne mon script :

[code:1]
PS> compare-textfile ref.txt dif.txt

Line Different Equal Characters
----


1 1 11 {@{Position=11; Reference=...
2 10 5 {@{Position=5; Reference= ...[/code:1]
Ah, intéressant. Le résultat s’affiche ligne par ligne. On peut voir que sur la première ligne on a un caractère de différent et onze caractères égaux (« Equal »). Sur la deuxième ligne, j’ai dix caractères différents et cinq égaux. Mais quelles sont ces différences ? Et qu’est-ce que c’est que ce charabia à la fin de chaque ligne ?

Voyons voir cela de plus près :

[code:1]
PS> $comp = compare-textfile ref.txt dif.txt
PS> $comp[0].characters

Position Reference Difference


11 !
[/code:1]
Ah, intéressant. La propriété Characters d’une ligne (ici, la première) est en fait un tableau qui contient la position de chaque différence, et pour chaque position le caractère de référence (celui présent ou pas à la position donnée dans le premier fichier passé en paramètre) ainsi que le caractère de différence (celui présent ou pas à la même position donnée dans le deuxième fichier passé en paramètre).

A ce stade, j’attire votre attention sur un point important : les numéros de ligne commencent à 1, mais les positions dans chaque ligne comment à 0. J’ai fait ce choix pour suivre les conventions les plus fréquemment rencontrées dans les numérotations de ligne : ouvrez un fichier dans un éditeur de texte évolué, vous verrez que la numérotation des lignes commence toujours à 1. A l’inverse, la numérotation des caractères dans une chaîne PowerShell commence toujours à 0. Le plus important est que vous soyez au courant de cette convention pour que vous puissiez en tenir compte.

Mais revenons à notre exemple. Regardons maintenant la deuxième ligne :

[code:1]
PS> $comp[1].characters

Position Reference Difference


5 , 6 H
7 O H
8 U O
9 P U
10 P
11 S
12 .
13 .
14 .
[/code:1]
On voit bien que là, contrairement à la première solution qui reposait sur compare-object, on a bien ici une prise en compte de la position des caractères. L’insertion de la virgule a déplacé la fin du texte ce qui provoque une cascade de différences jusqu’aux points de suspension.

Le script permet également de traiter les cas où les deux fichiers n’ont pas le même nombre de lignes. Les caractères présents dans les lignes supplémentaires deviennent autant de différences.

Je n’ai pas mis de commentaires dans le script lui-même. Je ne crois pas avoir introduit des choses que je n’ai pas déjà développées dans un billet précédent. Je préciserai juste pour finir que j’ai fait le choix d’utiliser les méthodes de la classe System.IO.File plutôt que la commandelette get-content pour pouvoir optimiser les performances si les fichiers à comparer contiennent plusieurs milliers de lignes voire plus. Cela dit, je n’ai pas testé sur de tels volumes, votre retour d’expérience sera apprécié si vous en avez l’occasion !

Ah, mais j’allais oublier le plus important ! Le problème initial posé sur le forum consistait à obtenir le nombre total de différences entre les deux fichiers. Or, ici je n’affiche les différences que ligne par ligne. Bigre, comment faire ? Allons, c’est insulter votre intelligence que de poser cette question. Et c’est faire plus belle insulte encore à PowerShell que de supposer qu’il n’y a pas une solution simple et élégante. Voyons voir :

[code:1]
PS> compare-textfile ref.txt dif.txt | measure-object different –sum[/code:1]
Hé oui, bien sûr.. Où avais-je la tête…

Janel

Message édité par: janel, à: 18/10/07 16:05<br><br>Message édité par: robin, à: 18/12/07 09:21

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

Plus d'informations
il y a 18 ans 5 mois #1199 par Arnaud Petitjean
Merci Janel pour la qualité de ton script et pour tous les commentaires qui vont avec !

Arnaud

MVP PowerShell et créateur de ce magnifique forum :-)
Auteur de 6 livres PowerShell aux éditions ENI
Fondateur de la société Start-Scripting
Besoin d'une formation PowerShell ?

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

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