Page 1 sur 2

extraire contenu entre différents items

Posté : mer. 13 févr. 2019 21:41
par fredmame
Bonsoir à tous,

je cherche à finaliser mon code pour extraire grace à autoit les données d'un unique fichier texte.
voila comment est constitué le fichier texte :
c'est une liste constituée de plusieurs catégories.
Chaque catégorie est nommée entre crochets et il n'y a pas de cohérence entre les noms
en dessous de cette categorie, il y a des noms de fichiers les uns en dessous des autres.

exemple:
fichier catégories.txt :
[blabla1]
1
2
3
[coucou2]
4
5
6
[hello]
8
9

la donnée dans une categorie peut se retrouver dans une autre, il peut y avoir des doublons mais ce sont des catégories uniques.


grace à stringbetween, j'arrive à extraire toutes les categories entre crochets et donc j'arrive bien à :
=>faire un fichier texte qui liste toutes les catégories (ca c'est un premier point que je voulais)
=>creer un fichier texte dont le nom est celui de chaque catégorie (ca c'est un point aussi que je voulais MAIS:

=>je ne sait pas comment mettre à l'intérieur de chaque fichier le contenu
il faudrait creer un fichier :
blabla1.txt qui se présente ainsi :
a
2
3

un fichier coucou2.txt qui se présente ainsi
4
5
6

etc.

une sorte de stringbetween lui meme dans un stringbetween ?
ou alors lire le resultat dans un tableau (ca c'est déja codé) et faire une recherche jusqu'au prochain caractere "[" qui est la catégorie suivante ?

voici ci-dessous mon code actuel
merci de vos idées.




#include <File.au3>
#Include <Array.au3>
#include <StringConstants.au3>
#include <String.au3>


Local $sfichieratrier, $afichieratrier,$aTRI,$sFile,$sString

; Sélection du fichier à filtrer.
$sfichieratrier = FileOpenDialog("Sélectionnez le fichier à filtrer", @WorkingDir & "\", "txt (*.txt)", $FD_FILEMUSTEXIST)
If @error Then
   MsgBox($MB_SYSTEMMODAL, "", "Aucun fichier sélectionné.")
   Exit
EndIf
; Transformation du résultat en tableau.
$afichieratrier = FileReadToArray($sfichieratrier)


;essai
MsgBox($MB_SYSTEMMODAL,"Affiche tout en tableau",fileread($sfichieratrier))


;ne garde que ce qui est entre crochets
Local $aTRI=_StringBetween(FileRead($sfichieratrier),"[","]")

_ArrayDisplay ($aTRI,"Affiche les catégories")




;ubound donne le nombre de lignes total mais les données commencent à zero
;je fais de 0 à total-1 en ajoutant 1

for $i = 0 to UBound($aTRI)-1  step +1
MsgBox($MB_SYSTEMMODAL,"test","voici le contenu de la ligne " &  $i & $aTRI[$i] )
next



;sauvegarder le listing des categories dans 1 fichier unique
$sFile = FileSaveDialog("Enregistrer sous...", @ScriptDir, "Text Files (*.txt) |  ini Files (*.ini) | All Files (*.*)", 18, "")
If @error Then Exit
$sString = _ArrayToString($aTRI , @crlf, Default, Default, @CRLF)
FileWrite($sFile, $sString)


;Crée automatiquement 1 fichier texte avec le nom de chaque categorie
;pour l'instant comme contenu toutes les categories mais il faudrait arriver à trier/filtrer les données entre chaque categorie
for $i = 0 to UBound($aTRI)-1  step +1
$file=fileopen($aTRI[$i] &".txt",1)
FileWrite($file,$aTRI[$i])
Next
MsgBox($MB_SYSTEMMODAL,"resultat",  UBound($aTRI) & "fichiers crées..." )

 

Re: extraire contenu entre différents items

Posté : mer. 13 févr. 2019 22:02
par Tlem
Bonsoir.
Les fonctions Ini d'AutoIt seront plus adaptées que la recherche par chaînes dans le fichier...

Edit : Je vous conseil de lire ce sujet : https://www.autoitscript.fr/forum/viewt ... 652#p65639

Re: extraire contenu entre différents items

Posté : mer. 13 févr. 2019 23:02
par fredmame
bonsoir,
fonction tres interressante que je vais explorer
merci du conseil.
je reviens quand j'ai avancé le projet.

Re: extraire contenu entre différents items

Posté : jeu. 14 févr. 2019 01:08
par Tlem
Bonsoir.

Après quelques tests, les fonctions Ini ne feront pas l'affaire, car les valeurs entre sections ne peuvent pas être lue (a cause de leur format <> xxx=zzz).
Du coup il faut chercher autre chose.

Je pense qu'une expression régulière devrait faire l'affaire, mais je suis resté coincé sur la capture des valeurs entre les sections. :(

Sinon, je crois me rappeler qu'une question similaire à été posée sur le forum. Je ne sais plus quand, mais peut être qu'avec une bonne recherche vous trouverez le sujet.

Cordialement

Re: extraire contenu entre différents items

Posté : jeu. 14 févr. 2019 09:23
par fredmame
merci de votre recherche.

pourtant cette fonction est très séduisante pour ce que j'ai testé dessus:
lecture via inireadsectionnames

il me restait à continuer mes test pour sortir avec inireadsection le reste... juste la clé, pas la valeur car il n'y en a pas

Je vais de toute façon aller au bout de ce projet, ca ne presse pas.
bonne journée.

ci-dessous le code : la partie inireadsectionnames marche parfaitement
je travaillais sur la suite qui n'est pas encore ok
#include <File.au3>
#Include <Array.au3>
#include <StringConstants.au3>
#include <String.au3>
#include <MsgBoxConstants.au3>

Local $sfichieratrier, $ini, $lop,$aArray

; Sélection du fichier à filtrer.
$sfichieratrier = FileOpenDialog("Sélectionnez le fichier à filtrer", @WorkingDir & "\", "txt (*.txt)", $FD_FILEMUSTEXIST)
If @error Then
   MsgBox($MB_SYSTEMMODAL, "", "Aucun fichier sélectionné.")
   Exit
EndIf




Local $ini = $sfichieratrier; on place le fichier ini dans une variable pour éviter de le ré-écrire.

$lop = IniReadSectionNames($ini) ; On place notre commande dans une variable
For $i = 1 To $lop[0] ;on commence la boucle pour analyser ligne par ligne le fichier
    MsgBox(0,"Voici les catégories","voici les categories via inireadsectionnames" & @CRLF  & $lop[$i]) ; on affiche le nom de la section pour chaque section

   Local $aArray = IniReadSection($sfichieratrier, $lop[$i])
    ;For $u = 1 To $aArray[0]
            MsgBox($MB_SYSTEMMODAL, "", "Clé: " & $aArray & @CRLF & "Valeur: " & $aArray[0])
       ; Next



 Next

 For $i = 1 To $lop[0] ; on s'apprête à lire toutes les lignes de la section
MsgBox(0,"catégories","clef : "&$lop[$i]) ; on affiche le nom de la clef et sa valeur pour chaque ligne
Next ; fin de la boucle, il n'y a plus rien dans la section

Re: extraire contenu entre différents items

Posté : jeu. 14 févr. 2019 15:48
par mikell
Voilà un petit code qui devrait faire le travail demandé
Si c'est OK, je peux si besoin expliquer plus en détail l'expression régulière utilisée

#Include <Array.au3>  ; juste pour le _ArrayDisplay

$txt = FileRead("catégories.txt")

$res = StringRegExp($txt, '(?x) \[ ([^\]]+) \]\R? ([^\[]*)', 3)
If IsArray($res) Then
   ; _ArrayDisplay($res)
   For $i = 0 to UBound($res)-2 step 2
       FileWrite($res[$i] & ".txt", $res[$i+1])
   Next
EndIf

Re: extraire contenu entre différents items

Posté : jeu. 14 févr. 2019 17:06
par fredmame
in-croy-able
Maitre Autoit !! !!

réponse à tout et avec du code ultra efficace :shock:

j'étais parti sur un tableau avec tout le listing
ensuite d'une analyse de la position numérique dans le tableau de chaque catégories
et faire un boucle de lecture du tableau en allant de la position +1 de la categories à la position -1 de la catégorie suivante.

Je vais essayer de comprendre l'expression réguliere.

Re: extraire contenu entre différents items

Posté : ven. 15 févr. 2019 00:17
par Tlem
Bonsoir Michel.
L'explication du pattern serait intéressante pour ceux qui veulent comprendre. ^^

Re: extraire contenu entre différents items

Posté : ven. 15 févr. 2019 12:34
par jchd
Tout petit bémol : cette regex part en sucette si l'un des noms de fichier contient un [
Je sais, je pinaille. Je n'y peux rien, il faut me supporter ainsi.

Re: extraire contenu entre différents items

Posté : ven. 15 févr. 2019 18:26
par mdanielm
Avec le même défaut levé par jchd:
$txt = FileRead("catégories.txt")
$a = stringsplit($txt, '[')
for $i=2 to $a[0]
   $b=stringsplit($a[$i], ']')
   FileWrite($b[1] & ".txt", stringmid($b[2],3)) ; pour oter crlf
Next

Re: extraire contenu entre différents items

Posté : ven. 15 févr. 2019 20:47
par mdanielm
Et sans le défaut, (impossible de traiter les fichiers de la forme [xxxxx] sans extension):
$txt=FileRead("catégories.txt")
$a = StringRegExp($txt, '(?x) \[ ([^\]]+) \]\R ', 1)
$p=@extended

do
   $b=StringRegExp($txt, '(?x) \[ ([^\]]+) \]\R ', 1, $p)
   $q=@extended
   if $q>0 then
      FileWrite($a[0] & ".txt", StringMid($txt, $p, $q-$p-stringlen($b[0])-4))
      $a=$b
      $p=$q
   endif
until $q=0
FileWrite($a[0] & ".txt", StringMid($txt, $p)) ;le dernier

Re: extraire contenu entre différents items

Posté : ven. 15 févr. 2019 21:06
par mikell
impossible de traiter les fichiers de la forme [xxxxx] sans extension
Mais à l'exception de ce cas aussi extrême qu'improbable, en voilà un qui devrait fonctionner.... jusqu'à la prochaine remarque constructive de jchd :mrgreen:

#Include <Array.au3>

$txt = FileRead("catégories.txt") & @crlf

$res = StringRegExp($txt, '(?msx) (^\s*\[ (.*?) \]\h*\R) (.*?)(?=(?1)|\z)', 3)

If IsArray($res) Then
    _ArrayDisplay($res)
   For $i = 1 to UBound($res)-2 step 3
       FileWrite($res[$i] & ".txt", $res[$i+1])
   Next
EndIf

"catégories.txt" utilisé pour le test :

[blabla1]
1
2[a
3
  [coucou2]
4]b
5 [c]
6
[hello]  
[8].txt
9

Re: extraire contenu entre différents items

Posté : ven. 15 févr. 2019 21:56
par mdanielm
Si un fichier s'appelle [toto], ce qui est très possible dans Windows, je ne peux pas le distinguer d'un nom de section, OK?


A part ce cas, tout fonctionne chez moi.
Ce n'est pas le cas pour ton script, essaie le fichier: [toto].jpg (en début de ligne)

Re: extraire contenu entre différents items

Posté : ven. 15 févr. 2019 22:11
par mikell
Bien sûr. Mais la vraie question est : est-ce que le créateur de ce sujet va créer dans sa liste de fichiers un élément qui aura le même nom qu'une section ? Surtout sans extension...
Il y a une différence entre une exception "possible" et une exception "plausible". Mettre un code en défaut on peut le faire, mais pour que ce soit constructif il faut que ce soit cohérent
La présence de crochets dans un nom de fichier est assez courante pour qu'on le note, l'existence de fichiers [toto] un peu moins Image

Re: extraire contenu entre différents items

Posté : ven. 15 févr. 2019 22:58
par mdanielm
Encore mieux:
; Admet: [toto].txt     [1]toto.txt     toto[1].txt
$txt=FileRead("catégories.txt") & "[FIN]" & @crlf
$a = StringRegExp($txt, '(?x) \[ ([^\]]+) \]\R ', 1)
$p=@extended

do
   $b=StringRegExp($txt, '(?x) \[ ([^\]]+) \]\R ', 1, $p)
   $q=@extended
   FileWrite($a[0] & ".txt", StringMid($txt, $p, $q-$p-stringlen($b[0])-4))
   $a=$b
   $p=$q
until $b[0]="FIN"

Re: extraire contenu entre différents items

Posté : dim. 17 févr. 2019 10:40
par fredmame
mikell a écrit : ven. 15 févr. 2019 22:11 Bien sûr. Mais la vraie question est : est-ce que le créateur de ce sujet va créer dans sa liste de fichiers un élément qui aura le même nom qu'une section ? Surtout sans extension...
Il y a une différence entre une exception "possible" et une exception "plausible". Mettre un code en défaut on peut le faire, mais pour que ce soit constructif il faut que ce soit cohérent
La présence de crochets dans un nom de fichier est assez courante pour qu'on le note, l'existence de fichiers [toto] un peu moins Image
Hello !!
merci merci merci
vous etes des As
je sens que ca vous amuse, c'est génial
je regarde ça de loin, je passe du temps à comprendre ce que vous écrivez en moins de 2.

Alors pour répondre à la question : c'est non
les catégories ont des noms qui ne peuvent etre repris dans la liste car dans les listes, les fichiers ont des extensions .zip
par contre selon les fichiers ini à "trier' je peux avoir des catégories notées ainsi :
[coucou / hello]
blabla.zip
blabla2.zip
test.zip
[coucou /miaou]
1.zip
2.zip
[test /sous section 1]
etc.


laissez moi quand meme essayer de faire des trucs moi-même !!

je pensais puisque ce projet avance à point que je n'imaginais meme pas, arriver à pouvoir choisir soit de faire catégorie par catégorie (ca c'est good) sauf que lorsqu'il y a la sorte de sous section, évidemment windows ne sait pas créer un fichier au nom "coucou /sous section1.ini

alors je pensais soit faire une modif de votre code pour faire un stringreplace du "/" par un "-"'

je pensais aussi pouvoir faire un choix supplémentaire de tri , soit en concatenant en 1 fichier ceux qui sont d'une meme categories (donc en fusionnant les sous sections soit en l'analysant pas ce qui est apres le "/"

désolé pour la réponse tardive et mes remerciements tardifs
bravo à vous.
bon weekend.
Fred.


ps:
je bosse quand meme,hein !!
voici ce que j'étais entrain de faire (évidemment entre temps vous avez modifié le code mais moi j'étais resté sur le code du début)
:ca demande le fichier, ini à trier et ca crée un dossier du nom du fichier et y place les fichiers de catégories.
(juste je re-précise que si j'ai [aventure / plateau] ca ne fait évidemment pas le fichier à cause du "/"
mais c'est pas grave pour l'instant.

je voudrais bien comprendre l'expression reguliere.
#Include <Array.au3>
#include <File.au3>
; juste pour le _ArrayDisplay


; Sélection du fichier à filtrer.


local $fichierini,$txt,$res,$dossier

$Fichierini= FileOpenDialog("Sélectionnez le fichier ini", @WorkingDir & "\", "ini (*.ini)", $FD_FILEMUSTEXIST)
If @error Then
   MsgBox($MB_SYSTEMMODAL, "", "Aucun fichier sélectionné.")
   Exit
EndIf



$txt = FileRead($fichierini)
$nom=StringRegExpReplace($fichierini, "^.*\\|\..*$", "")

$dossier = DirCreate("filtres-"&$nom)


$res = StringRegExp($txt, '(?x) \[ ([^\]]+) \]\R? ([^\[]*)', 3)
If IsArray($res) Then
   _ArrayDisplay($res)





   For $i = 0 to UBound($res)-2 step 2
       FileWrite("filtres-"&$nom &"\" &$res[$i] & ".txt", $res[$i+1])
   Next
EndIf



;(?x)
;Étendu : les espaces blancs à l'extérieur des classes de caractères sont ignorés
;et # démarre un commentaire jusqu'au prochain caractère Newline dans le modèle.
;L'espacement des éléments rend les expressions régulières beaucoup plus lisibles.
;Par défaut, les espaces blancs et # sont interprétés littéralement.

Re: extraire contenu entre différents items

Posté : dim. 17 févr. 2019 14:11
par mikell
En utilisant le modèle que tu viens de poster, il y aurait bien ça, mais je ne sais pas si c'est ce que tu cherches. La manière dont tu veux gérer les sous-sections est assez floue :mrgreen:

#Include <Array.au3>

$txt = FileRead("catégories.txt") & @crlf

$res = StringRegExp($txt, '(?msx) (^\s*\[ ([^\]\r\n]*) \]\h*\R) (.*?)(?=(?1)|\z)', 3)

If IsArray($res) Then
    ;_ArrayDisplay($res)
   For $i = 1 to UBound($res)-2 step 3
       $split = StringSplit(StringStripWS($res[$i], 8), "/")
       If $split[0] = 1 Then
          FileWrite(@scriptdir & "\" & $res[$i] & ".txt", $res[$i+1])
          ContinueLoop
       Else
          $dir = @scriptdir & "\" & $split[1]
          If not FileExists($dir) Then DirCreate($dir)
          FileWrite($dir & "\" & $split[2] & ".txt", $res[$i+1])
       EndIf
   Next
EndIf

Re: extraire contenu entre différents items

Posté : dim. 17 févr. 2019 20:07
par fredmame
Mais si c'est ca, c'est magique...
Vous etes les Maîtres du code .
un dossier par catégorie, et dans chaque dossier la "sous catégories"

Je voudrais quand même comprendre ce (?msx) (^\s*\[ (.*?) \]\h*\R) (.*?)(?=(?1)|\z)
c'est commun à notepad++ ou bien y a t'il des specificités avec autoit ?

en tous cas, autoit c'est sacrément puissant... dire que moi j'utilisais ca pour faire des trucs à la c.. j'en ai honte.
c'est un langage à part entiere.

merci de votre aide et de votre disponibilité.
sans vous , resultat zéro
mais j'ai progressé et encore plus envie de comprendre .

Bonne fin de weekend à tous
FRED.

Re: extraire contenu entre différents items

Posté : lun. 18 févr. 2019 12:31
par mikell
fredmame a écrit :Je voudrais quand même comprendre ce (?msx) (?msx) (^\s*\[ (.*?) \]\h*\R) (.*?)(?=(?1)|\z)
Voilà des explications. Surtout sur le concept, parce que pour les détails de syntaxe le fichier d'aide est là pour ça
Je vais essayer d'être clair

Edit : regex revu après que mdanielm m'ait fait remarquer que j'avais usé d'un raccourci coupable :oops:

(?msx) (^\s*\[ ([^\]\r\n]*) \]\h*\R) (.*?)(?=(?1)|\z)

Les options :
(?x) : pour ignorer les espaces blancs dans l'expression quand on les met juste pour améliorer la lisibilité
(?s) : pour que le point représente n'importe quel caractère y compris les retours à la ligne
(?m) : option 'multiline' pour que ^ représente un début de ligne

Ce qui complique le regex c'est le problème soulevé par jchd et mdanielm : les crochets possibles dans les noms de fichier. ça impose d'être rigoureux dans la manière dont on définit un nom de section dans l'expression, pour pouvoir ensuite poser une condition quand on définit le contenu de la section

pour les sections :
(^\s*\[ ([^\]\r\n]*) \]\h*\R) : groupe capturant n°1 qui matche la ligne complète d'un nom de section avec son retour à la ligne
"début de ligne, 0 ou plus espace, crochet ouvert, 0 ou plus caractères qui ne sont ni un crochet fermé ni un retour à la ligne , crochet fermé, 0 ou plus espace horizontal, newline sequence"
Au passage le nom de la section est capturé dans le groupe n°2 : ([^\]\r\n]*)

pour les contenus :
(.*?) (?= (?1)|\z) : groupe capturant n°3 et son lookahead
"0 ou plus caractères (lazy), suivis par quelque chose susceptible d'être matché par (?1) ou par la fin du texte"
(?1) représente le pattern du groupe capturant n°1, donc la définition d'un contenu est :
"0 ou plus caractères (lazy) y compris les retours à la ligne, suivis par une ligne de nom de section ou par la fin du texte"

Remarques
- la seule chose qui peut prendre le regex en défaut serait un nom de fichier matché par le pattern du groupe n°1
- le regex accepte de retourner des noms de section ou des contenus vides, mais pour ça il faut rajouter un @crlf au texte :
$txt = FileRead("catégories.txt") & @crlf
- à chaque "passage", 3 groupes sont retournés (ligne de section + nom de section + contenu de la section), d'où le "step 3" de la boucle For qui lit l'array ensuite (voir le _ArrayDisplay)
- si j'ai dit une connerie quelque part je compte bien sur jchd (qui est un VRAI maître, lui) pour le signaler :mrgreen:

Re: extraire contenu entre différents items

Posté : lun. 18 févr. 2019 21:07
par jchd
AutoIt utilise les regexp PCRE1 (qui date déjà un peu). Depuis l'auteur de PCRE a sorti PCRE2, mais il n'y a de différences majeures du point de vue du "langage" utilisé.

Le site PCRE (v2 en anglais) mais la doc proposée par AutoIt couvre la grande majorité des besoins.

Le site http://regex101.com/ permet de tester les regexp, déboguer, obtenir une explication détaillée de chaque patron, etc.