Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

VBScript Discussion :

Contrôle de l'intégrité d'un fichier balisé


Sujet :

VBScript

  1. #1
    Membre actif
    Contrôle de l'intégrité d'un fichier balisé
    Bonjour,

    j'ai besoin de créer un script en VBS permettant de vérifier l'intégrité d'un fichier balisé de plusieurs centaines / milliers de lignes et je ne sais pas trop comment m'y prendre...

    A l'exécution de ce script, celui-ci doit ouvrir un fichier TXT ou XML et en lire chaque ligne :

    - Identifier une balise d'ouverture (par ex. : <Mon_exemple>)
    - Mettre en mémoire le nom de cette balise ainsi que la ligne ou elle se trouve
    - Continuer à lire le fichier et identifier une balise de fermeture (par ex. : </Mon_exemple>)
    - Si le nom des balises d'ouverture et de fermeture est identique, supprimer le nom de la balise (Mon_exemple) en mémoire ainsi que la ligne ou elle se trouve

    En fin de lecture du fichier, afficher le nom des balises "orphelines" (qu'elles soient d'ouverture ou de fermeture) ainsi que les lignes ou elle se trouvent.

    Dans cet exemple, les balises "Info_2" - ligne 3 et "Info_4" - ligne 5 sont orphelines :

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    <Balise_1>
    <Info_1>Mon info 1</Info_1>
    <Info_2>Mon info 2
    <Info_3>Mon info 3</Info_3>
    Mon info 4</Info_4>
    <Info_5>Mon info 5</Info_5>
    </Balise_1>
    <Balise_1>Mon info 6</Balise_1>




    Note : Une balise du même nom peut être déclarée plusieurs fois dans le fichier à condition qu'elle soit refermée avant qu'elle soit ouverte de nouveau (lignes 1, 7 et 8)

    SVP, avez-vous des pistes / idées à me proposer ?
    "L'erreur est humaine mais un véritable désastre nécessite un ordinateur." de William Henry, dit Bill Gates

  2. #2
    Membre actif
    Personne que cela inspire ? Ma demande n'est pas assez claire ?
    "L'erreur est humaine mais un véritable désastre nécessite un ordinateur." de William Henry, dit Bill Gates

  3. #3
    Rédacteur

    bonjour,
    Ma demande n'est pas assez claire ?
    très claire au contraire mais j'ai besoin encore d'un peu de temps
    pour te proposer quelque chose car je suis assez occupé
    et la gestion des lignes complique pas mal l'algo
    nomen omen, nemo non omen - Consultez la FAQ VBScript et les cours et tutoriels VBScript
    le plus terrible lorsqu'une voiture renverse un piéton, c'est que ce sont les freins qui hurlent. (ramón)
    pas de questions techniques par mp

  4. #4
    Membre actif
    Super, merci...
    "L'erreur est humaine mais un véritable désastre nécessite un ordinateur." de William Henry, dit Bill Gates

  5. #5
    Rédacteur/Modérateur

    Salut

    Moi j'en suis là, mais je pense que algorithme n'est pas très solide, il faudrait plus de ligne pour améliorer et peut être passer par un RegExp avec Pattern = "(<[A-Za-z0-9_]*>)" 'pour trouver toutes les balises d'ouverture et Pattern = "(</[A-Za-z0-9_]*>)" 'pour trouver toutes les balises de fermeture.
    En attendant ...
    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
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    Dim LeFichier 'pour simuler le contenu du fichier
    LeFichier = "<Balise_1>" & vbnewline _
    & "<Info_1>Mon info 1</Info_1>" & vbnewline _
    & "<Info_2>Mon info 2" & vbnewline _
    & "<Info_3>Mon info 3</Info_3>" & vbnewline _
    & "Mon info 4</Info_4>" & vbnewline _
    & "<Info_5>Mon info 5</Info_5>" & vbnewline _
    & "</Balise_1>" & vbnewline _
    & "<Balise_1>Mon info 6</Balise_1>"
     
    Dim Memo
    Call(Trier)
    MsgBox "Balise(s) orpheline(s) " & vbnewline & vbnewline & Memo
     
    '*******************************************************************************
    Sub Trier()
    Dim Cpt, PosDeb, PosFin, PoS
    Dim TblLg, TblCol, BaliseDeb, BaliseFin
     
    TblLg = split(LeFichier,vbnewline)
    For Cpt = 0 to Ubound(TblLg)
            PosDeb = Instr(1,TblLg(Cpt),"<",0)+ 1
            PosFin = Instr(PosDeb,TblLg(Cpt),">",0)
            BaliseDeb = Mid(TblLg(Cpt),PosDeb,PosFin-PosDeb)
            'MsgBox "BaliseDeb = " & BaliseDeb,,"première recherche"
            If Left(BaliseDeb,1) ="/" Then
                    'MsgBox "balise fermente: " & BaliseDeb
                    BaliseFin = "<" & BaliseDeb & ">"
                    BaliseDeb = "<" & replace(BaliseDeb,"/","") & ">"
                    Pos = InStrRev(LeFichier,BaliseDeb,PosFin,0)
                    If Pos=0 Then
                            Memo = Memo & "ligne " & Cpt+1 & ": " & BaliseFin & vbnewline
                    End If
                    Else
                    'MsgBox "balise ouvrente: " & BaliseDeb
                    BaliseFin = "</" & BaliseDeb & ">"
                    BaliseDeb = "<" & BaliseDeb & ">"
                    Pos = Instr(PosFin,LeFichier,BaliseFin,0)
                    If Pos=0 Then
                            Memo = Memo & "ligne " & Cpt+1 & ": " & BaliseDeb & vbnewline
                    End If
            End If
    Next
    End Sub
    '*******************************************************************************
    Soyez sympa, pensez -y
    Balises[CODE]...[/CODE]
    Balises[CODE=NomDuLangage]...[/CODE] quand vous mettez du code d'un autre langage que celui du forum ou vous postez.
    Balises[C]...[/C] code intégré dans une phrase.
    Balises[C=NomDuLangage]...[/C] code intégré dans une phrase quand vous mettez du code d'un autre langage que celui du forum ou vous postez.
    Le bouton en fin de discussion, quand vous avez obtenu l'aide attendue.
    ......... et pourquoi pas, pour remercier, un pour celui/ceux qui vous ont dépannés.

  6. #6
    Membre actif
    @ProgElecT, pour un premier jet, c'est déjà super...

    ça correspond tout à fait à mon besoin :-) :-)
    "L'erreur est humaine mais un véritable désastre nécessite un ordinateur." de William Henry, dit Bill Gates

  7. #7
    Rédacteur/Modérateur

    Citation Envoyé par steph78630 Voir le message
    ...vérifier l'intégrité d'un fichier balisé de plusieurs centaines / milliers de lignes....
    Citation Envoyé par steph78630 Voir le message
    ....ça correspond tout à fait à mon besoin :-) :-)
    Cela fonctionne sur les centaines de lignes? alors là, ça m'épate, en tout cas tant mieux si cela a réglé ton problème.
    Soyez sympa, pensez -y
    Balises[CODE]...[/CODE]
    Balises[CODE=NomDuLangage]...[/CODE] quand vous mettez du code d'un autre langage que celui du forum ou vous postez.
    Balises[C]...[/C] code intégré dans une phrase.
    Balises[C=NomDuLangage]...[/C] code intégré dans une phrase quand vous mettez du code d'un autre langage que celui du forum ou vous postez.
    Le bouton en fin de discussion, quand vous avez obtenu l'aide attendue.
    ......... et pourquoi pas, pour remercier, un pour celui/ceux qui vous ont dépannés.

  8. #8
    Membre actif
    Citation Envoyé par ProgElecT Voir le message
    Cela fonctionne sur les centaines de lignes?...
    Oups ! Désolé, on s'est mal compris

    Je voulais dire que ton code est pile ce que j'espérais et déjà super content de cet essai.


    Je l'ai maintenant testé sur l'un de mes fichiers de 24 000 lignes - en résultat :

    - J'ai de nombreuses balises d'ouverture et de fermeture qui passent bien,
    - J'ai aussi des balises de fermeture déclarées "orphelines" alors qu'elles ne le sont pas dans le fichier
    - Je n'ai aucune balise d'ouverture déclarée orpheline

    - Demain, je vais analyser de plus près le contenu du fichier balisé pour voir ce qui ne fonctionne pas

    Autrement, je m'interroge sur la concaténation des infos de balises orphelines dans MEMO (lignes 32 et 40), vérifié à chaque ligne lue du fichier avec la boucle For :

    > N'est-il pas un peu tôt pour déclarer une balise orpheline ? (ceci dit, cela fonctionne très bien pour certaines)
    "L'erreur est humaine mais un véritable désastre nécessite un ordinateur." de William Henry, dit Bill Gates

  9. #9
    Rédacteur

    bonjour,
    problème assez complexe donc intéressant
    ça tombe bien car je cherchais justement un exemple pour illustrer
    un projet d'article sur la pratique des expressions régulières
    mais je ne savais pas comment devaient être traitées les balises
    réciproquement imbriquées de même niveau
    ex :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    <A><B></A></B>

    il y a 3 possibilités : aucun tag orphelin, tous les tags sont orphelins ou seuls <B> et <\B> le sont...
    le présent code va au plus simple...(si on peut dire) c'est à dire qu'il considère que toutes les paires de tag sont valides
    à tester
    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
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    ' ************************************************************************
    ' GetOrphanTags - omen999 - https://omen999.developpez.com - november 2020
    ' ************************************************************************
    Dim reg, crlfmatches, tagmatches, orphmatches
    Dim atags(), apos(), aline(), adata, lstags, lsrep
    Dim strict : strict = 0
    Dim result
     
     
    stext = "<Info_999><Balise_1>infoXX" & vbCrLf &_
    "<Info_1>Mon info 1</Info_1>" & vbCrLf &_
    "<Info_2>Mon info 2" & vbCrLf &_
    "<Info_3>Mon info 3<Info_3>Info3_imbriquée</Info_3></Info_3>" & vbCrLf &_
    "Mon info 4</Info_4>" & vbCrLf &_
    "<Info_5>Mon info 5</Info_5>" & vbCrLf &_
    "</Balise_1>szer</Info_10>" & vbCrLf &_
    "<Balise_1>Mon info 6</Info_2></Balise_1><Info_9>"
     
    Function cbReplaceProc(match, sub1, pos, source)
      cbReplaceProc = String(Len(match), "#") ' renvoi du nombre magique
    End Function
    Function cbReplaceInvProc(match, sub1, sub2, pos, source) ' à réviser ultérieurement
      ' strict interdit la validation de tags orphelins validés a posteriori par des suppressions de paire de tags conformes
      ' pas efficace pour les tags réciproquement imbriqués
      If strict > pos Then
        cbReplaceInvProc = match 
      Else
        strict = pos
       cbReplaceInvProc = String(Len(sub1) + 2, "#") & sub2 & String(Len(sub1) + 3,"#")
      End If
    End Function
     
    Set reg = New RegExp : reg.IgnoreCase = True: reg.Global = True
     
    ' repérage des lignes
    reg.Pattern = "\r\n"
    Set crlfmatches = reg.Execute(stext)
    ' extraction de tous les tags
    reg.Pattern = "<(?<img src="images/smilies/icon_neutral.gif" border="0" alt="" title=":|" class="inlineimg" />\/).+?>"
    Set tagmatches = reg.Execute(stext)
    ReDim atags(tagmatches.Count - 1)
    ReDim apos(tagmatches.Count - 1)
    ReDim aline(tagmatches.Count - 1)
    adata = Array(atags,apos,aline) ' regroupe 3 tableaux simple dimension sans perdre la fonction Join
    For n = 0 To tagmatches.Count - 1
      adata(0)(n) = tagmatches(n)
      adata(2)(n) = 1
      For i = 0 To crlfmatches.Count - 1
        If tagmatches(n).FirstIndex > crlfmatches(i).FirstIndex Then adata(2)(n) = i + 2
      Next
    Next
     ' tous les tags extraits regroupés en une nouvelle chaine cible
    lstags = Join(adata(0),"")
     ' maj des index des tags de la nouvelle cible
    Set tagmatches = reg.Execute(lstags)
    For n = 0 To tagmatches.Count - 1
      adata(1)(n) = tagmatches(n).FirstIndex
    Next
    ' élimination des tags sans tag orphelin imbriqué
    ' pour ne pas modifier le tableau des index tags, on remplacera les tags éliminés par un "nombre magique" de même taille (chaine de #)
    reg.Pattern = "<(.+)>#*?<\/\1>"   ' maj pattern pour gérer nombre magique 
    lsrep = lstags
    Do
      lstags = lsrep
      lsrep = reg.Replace(lstags,GetRef("cbReplaceProc"))
    Loop Until lsrep = lstags
     ' élimination des tags avec tag orphelin imbriqué
    reg.Pattern = "<(.+)>(.+?)<\/\1>"
    Do
      lstags = lsrep
      lsrep = reg.Replace(lstags,GetRef("cbReplaceInvProc"))
    Loop Until lsrep = lstags
    reg.Pattern = "<(?<img src="images/smilies/icon_neutral.gif" border="0" alt="" title=":|" class="inlineimg" />\/).+?>"
    Set orphmatches = reg.Execute(lsrep)
    ' collection de tous les tags orphelins
    ' un traitement supplémentaire est nécessaire pour ramener le numéro de ligne stocké dans adata(2)
    result = ""
    For n = 0 to orphmatches.Count - 1
      For i = 0 to UBound(adata(1))
        If orphmatches(n).FirstIndex = adata(1)(i) Then result = result & orphmatches(n) & vbTab & " n° de ligne : " & adata(2)(i) & vbCrLf
      Next
    Next
    MsgBox result
    nomen omen, nemo non omen - Consultez la FAQ VBScript et les cours et tutoriels VBScript
    le plus terrible lorsqu'une voiture renverse un piéton, c'est que ce sont les freins qui hurlent. (ramón)
    pas de questions techniques par mp

  10. #10
    Rédacteur/Modérateur

    Salut

    J'ai refait le fichier d'omen999 à la main en l'intentant

    <Info_999>
          <Balise_1>infoXX
                <Info_1>Mon info 1</Info_1>
                <Info_2>Mon info 2
                <Info_3>Mon info 3<Info_3>Info3_imbriquée</Info_3></Info_3>
                Mon info 4</Info_4>
                <Info_5>Mon info 5</Info_5>
          </Balise_1>
          szer</Info_10>
    <Balise_1>
          Mon info 6</Info_2>
    </Balise_1>
    <Info_9>
    En rouge les balises orphelines, en vert et bleu balises non orphelines
    d'accord avec moi ou pas ?
    Si oui,
    <Info_999>
    <Info_2>
    </Info_4>
    </Info_10>
    </Info_2>
    <Info_9>
    doivent être considérées comme balises orphelines.

    Ben s'est pas de la tarte pour trouver l'algorithme, me je n'y suis pas parvenu.

    omen999 , , ton algorithme a bien l'air d'être solide
    Soyez sympa, pensez -y
    Balises[CODE]...[/CODE]
    Balises[CODE=NomDuLangage]...[/CODE] quand vous mettez du code d'un autre langage que celui du forum ou vous postez.
    Balises[C]...[/C] code intégré dans une phrase.
    Balises[C=NomDuLangage]...[/C] code intégré dans une phrase quand vous mettez du code d'un autre langage que celui du forum ou vous postez.
    Le bouton en fin de discussion, quand vous avez obtenu l'aide attendue.
    ......... et pourquoi pas, pour remercier, un pour celui/ceux qui vous ont dépannés.

  11. #11
    Rédacteur

    ton algorithme a bien l'air d'être solide
    solide mais pas bulletproof il y a un cas limite peut-être rare qui pose problème
    en ce qui concerne les tags imbriqués un contrôle de validité pourrait être ajouté
    avec le parser du composant "xml dom document" ProgID : "Microsoft.XMLDOM.1.0"
    pour lever le doute
    nomen omen, nemo non omen - Consultez la FAQ VBScript et les cours et tutoriels VBScript
    le plus terrible lorsqu'une voiture renverse un piéton, c'est que ce sont les freins qui hurlent. (ramón)
    pas de questions techniques par mp

###raw>template_hook.ano_emploi###