# Environnements de dveloppement > Delphi > Codes sources  tlcharger >  Classe TArrayObject et fonction BinaryStringReplace

## KlausGunther

Pour des besoins dans mes logiciels personnels, j'avais besoin d'une fonction qui puisse remplacer dans un fichier quelconque, dans un seul appel, plusieurs critres par d'autres, et ce indiffremment en format texte ou binaire.

La difficult (pour moi, en tout cas...) tait de pouvoir passer  la fonction des tableaux de strings ou de "array of array of byte" et de les traiter indiffremment dans ma fonction. Voici ma solution que je propose de partager (et pour laquelle des comentaires ou amliorations sont les bienvenus).

J'ai cr une unit ArrayObject.pas qui contient mon implmentation d'un objet capable d'encapsuler aussi bien des "array of string" que des "array of array of byte" et de les traiter en faisant abstraction de leur contenu rel. Et j'ai fait une unit RBS qui contient ma fonction utilisant ces nouveaux objets.

Tout est dans le fichoer ZIP en pice jointe avec le projet complet d'un programme de dmo permettant de slectionner un fichier et de le traiter, en forant un suffixe "_converted"  la fin du nom de fichier. Un petit fichier demo1.txt est joint galement.

J'ai failli oublier: tout cela est ralis en Delphi 6 Personal Edition.

----------


## ShaiLeTroll

Pourquoi CreateNew comme constructeur ?
Ajoute un *const* pour tes paramtres *string* non modifi dans la fonction qui les reoit avec le BrlndMM c'est un gain de temps
faudrait travailler sur virtual et override pour utiliser le polymorphisme au lieu d'une encapsulation.

Pour la fonction de remplacement, peut-tre utiliser des Event  la place de la dpendance au TMemo/ProgressBar
Que ce passe-t-il si un OldPattern est  cheval sur deux Buffers ?

----------


## Paul TOTH

j'ai pas tout regard mais quand je vois a je dis ouille !



```

```

la moindre des choses serait de dclarer


```

```

----------


## KlausGunther

Merci  vous deux pour vos remarques. J'avoue que je n'ai pas regard du ct de virtual, abstract, override. Faudra que j'approfondisse cela car pour le moment, cela m'chappe. Mais je vais m'y mettre !

Concernant la remarque sur un pattern  cheval sur deux buffeurs, tel que j'ai conu la chose, cela ne devrait pas arriver. Le lis un buffeur d'une longueur dfinie par une constante (32 ko dans la version actuelle), mais je limite l'analyse  une partie rduite. En fait, je dtermine les longueurs minimales et maximales des critres et j'arrte la recherche ds que je suis trop prs de la limite du buffeur. Puis, je reprends la lecture, non pas l o le l'avais laisse, mais l o j'avais arrt l'analyse,  savoir  une distance quivalente  la longueur minimale des critres. Ainsi, cette partie non analyse se retrouvera au dbut du buffeur lors de la prochaine lecture et le critre pourra tre trouv.

En rdigeant ces lignes, je me rends compte qu'il aurait fallu s'arrter  une distance correspondant  la longueur du plus long critre et non du plus court. Le fichoer ZIP ci-joint contient cette correction. Pas encore les modifictations selon vos conseils techniques - faut que je comprenne d'abord.

Merci pour vos remarques - je remets l'ouvrage sur le mtier...

----------


## KlausGunther

> j'ai pas tout regard mais quand je vois a je dis ouille !


Ben... j'ai d mal m'exprimer dans mon post initial.

Je voulais crer une classe (TArrayObject dans mon cas) qui est capable de contenir et grer deux classes diffrentes (TStringArray et TByteArrar dans moncas). Ma classe TArrayObject, via des proprits et mthodes gnrales, devait pouvoir grer les classes dpendantes de faon transparente, sans que je sache, vu de m'extrieur, quelle classe est contenue  l'intrieur de TArrrayObject. 

Pour cette raison, je cre ma classe TArrayObject en lui indiquant le type de classe interne  crer ainsi que sa dimension, comme dans:


```
  OldPat := TArrayObject.CreateNew(atStringArray,2);
```

Ensuite, j'agis uniquement syr TArrayObject, comme par exemple pour charger sonn contenu:


```

```

Ensuite, je n'utilise que TArrayObject (OldPat dans ce cas) pour trairer les patterns qui s'y trouvent. Vu de l'application, j'ignore tout du contenu et de la structure interne de TArrayObject. Avec la suggestion de VIRTUAL et OVERRIDE, j'ai l'impression qu'on inverse le raisonnment: on cre une classe "parent" dont on "drive" deux classes "enfant", chacune ayant les mmes mthodes. Je fais a souvent dans d'autres contextes, mais ceci ne me permet pas de passer un identifiant unique  ma fonction de de le traiter dans ma fonction sans qu'elle sache ce que la classe passe en paramtre contient reellement.

Ceci dit, en rflchissant  tout cela, j'ai dcouvert un rsidu de code provenant de mes premiers essais, qui est obsolte et qui brouille donc la comprhension, dans le programme principal. Je l'ai supprim, et la version apure est dans le ZIP  ci-joint. Ainsi, le programme principal ne connat que TArrayObject, de mme que la fonction dans l'unit RBS. Les "helper class" nommes TStringArray et TByteArray ne sont jamais utilises explicitement. Tout l'intrt de la chose se situe l.

----------


## ALWEBER

Il faut approfondir certaines notions comme le TStrings et TStringlist avant d'aller plus loin pour ne pas recrer ce qui existe dj. Si besoin est je peux te passer des extraits du livre que j'ai crit sur Delphi

----------


## KlausGunther

@ ALWEBER

Merci de ta proposition. Je suis toujours preneur quand le peux apprendre quelque chose.
Je connais bien TStringList que j'utilise souvent. 
Je suis beaucoup mois  l'aise avec TStrings que je n'utilise jamais directement.

Ceci dit, si mon besoin tait de passer uniquement des listes de chanes de caractres en paramtre, j'aurais bien sr utilise une TStringList
avec le critre de recherche comme texte de chaque lment et le critre de remplacement en tant qu'objet comme objet associ.
Malheureusement, cela ne marche pas avec des critres binaires pouvant contenir des octets "difficiles" comme des zros binaires.
L, seul un "array of array of byte" est possible, encapsul dans mon implmentation dans un TByteArray.
Ceci tait la raisin initiale de la cration de mon objet TArrayObject, grant de faon transparente des tableaux de strings et 
des tableaux de byte en 2 dimension, ce qui correspond  des "strings binaires".

J'ai supprim des rsidus de traage dans la fonction, issus de ma phase de debug. 
En fichier ZIP joint, voici la versioin "nettoye".

----------


## Andnotor

> ...de le traiter dans ma fonction sans qu'elle sache ce que la classe passe en paramtre contient reellement.


C'est la dfinition mme du polymorphisme  :;): 

Le problme est que tu instancies directement _TArrayObject_ ce qui t'oblige  conserver une rfrence sur le type rel et de procder  des tests systmatiques sur chaque fonction.
Utiliser une mthode de classe plutt qu'instancier directement _TArrayObject_ te permettrait de retourner ce type rel et de te passer de tous ces tests.



```

```

----------


## KlausGunther

Je vais essayer, Andnotor !

----------


## Paul TOTH

bon alors on reprend, car c'est le principe mme de la programmation oriente objet

quand j'utilise un TStream par exemple, j'ignore si c'est un TFileStream, un TMemoryStream, un TResourcceStream, ou quoi que ce soit d'autre...car ils sont tous descendants de TStream et j'utilise les mthodes de TStream sans me proccuper de savoir si c'est un fichier, une zone mmoire ou une ressource.

quand tu cris:


```

```

tu codes le principe mme d'un objet mais sans faire de l'objet

TArrayObject.ElementCount ne sais pas ce qu'il doit retourner de lui-mme, donc mthode virtuelle (et abstraite ou pas selon qu'on veuille faire une implmentation par dfaut qui retourne -1 ou pas)

TStringArray et TByteArray connaissent leur nombre d'lments, donc ils surchargent la mthode pour donner leur rponse.

et  l'usage tu pourras crire


```

```

mais pour pouvoir crire cela il faut que TByteArray et TStringArray drivent de TArrayObject

----------


## KlausGunther

Merci, Paul Toth !

L, je comprends mieux. Je vais tenter d'appliquer tout cela et reviendrai avec le rsultat.

----------


## KlausGunther

Voil ma nouvelle version aprs implmentation de mthodes virtuelles abstraites dans la classe TArrayObject, selon les conseils de Paul TOTH.

En effet, c'est beaucoup plus simple et beaucoup plus propre. A l'excution, le rsultat est identique.

Un grand MERCI - j'ai appris une chose importante qui me sera utile !

----------


## Paul TOTH

ok, c'est plus propre, mais encore deux petites remarques

le constructor est suppos s'appeler Create et non CreateNew, ce n'est pas une contrainte c'est une bonne pratique, TForm possde un constructor CreateNew mais il a un usage particulier car il ne charge pas le DFM

les destructors ne servent  rien dans le cas prsent, les tableaux dynamiques sont des types manags, ils sont automatiquement dtruits par Delphi

----------


## KlausGunther

D'accord. J'ai supprim le destructor et remplac CreateNew r Create. 
J'ai donc d crer une nouvelle mthode SetArrayLength pour remplacer mon paramtre de CreateNew.
Tout fonctionne  nouveau. Ci-joint la nouvelle version.

----------


## Paul TOTH

> D'accord. J'ai supprim le destructor et remplac CreateNew r Create. 
> J'ai donc d crer une nouvelle mthode SetArrayLength pour remplacer mon paramtre de CreateNew.
> Tout fonctionne  nouveau. Ci-joint la nouvelle version.


il est tout  fait possible de mettre des paramtres  un constructor quelque soit son nom



```

```

tu pourrais mme faire un 



```

```

et encore c'est car je reste compatible D5/6/7, sinon je serais passer par un TArray<string> qu'on peut affecter directement  fStringArray

en D5/6/7 un "const x:array of string" est un tableau ouvert et non un tableau dynamique, ce n'est pas la mme chose. Dans les dernires versions, on peut dclarer un tableau dynamique directement.

----------


## KlausGunther

D'accord. Merci pour cela - je vais noter a pour un usage ultrieur. 
Dans le contexte de l'objet TArrayObject, je prfre finalement garder Create sans paramtres
et utiliser la mthode SetArrayLength ce qui me permettra, le cas chant, de changer dynamiquement la dimension.

Merci pour ce cours magistral qui m'a fait bien progresser.

----------


## ALWEBER

Ci joint un peu de doc  comme promis

----------


## KlausGunther

Merci beaucoup, AlWeber ! J'ai jet un rapide coup d'oeil et je vois qu'il me reste plein de choses  apprendre, en particulier les interfaces, mais pas que.
J'aurai de quoi occuper mes soires.

A toutes fins utiles, je joins la toute dernire version de mon code, contenant les adaptations suggres par Paul Toth, deux nouvelles mthodes permettant de charger les attays  partir de TStrinList, TMemo ou TListbox et une interface visuelle permettant de saisir les critres de recherche/remplacement pour la fonction de remplacement. Ces objets sont passs en paramtre (pour utilisation directement par Delphi) ou par handle (sauf TStringList bien sr) pour utilisation de ce code dans une DLL appele par un programme non-Delphi (Panoramic dans mon cas). Je sais, a ne change rien sur le fond, mais c'est juste un plus pour la facilit d'utilisation.

----------


## Paul TOTH

tu n'as vraiment pas les rflexes de la programmation objet  :;): 

TStringList, TMemo.Lines et TListBox.Items sont tous les trois drivs de TStrings qui reprend ce principe d'anctre commun, tu devrais donc simplement dclarer LoadArrayFromStrings(Strings: TStrings)

par ailleurs, ton anctre commun TArrayObject n'a pas besoin d'tre purement virtuel, il peut trs bien implmenter cette fonction en utilisant SetArrayLength() et LoadArrayElementFromString()



```

```

et c'est l toute la beaut de l'objet, une seule fonction pour charger les strings sans mme savoir  quoi tu as affaires et a marche dans tous les cas car tu sais que tous les drivs de TArrayObject surchargent SetArrayLength() et LoadArrayElementFromString()

au bout de 25 ans de programmation objet, ces mcanismes deviennent des automatismes  ::): 

le premier principe que j'applique c'est que si deux fonctions se ressemblent  90% c'est qu'il y a trs probablement moyen de la transformer en une seule fonction avec ventuellement un paramtre en plus ou - comme dans le cas prsent - la recherche d'un anctre commun

et avec les dernires versions tu peux ajouter des fonctions utiles (mme si je ne suis pas forcment fan)



```

```

le fait de mettre "inline" implique que la fonction ne sera pas une fonction mais directement le code ajout l o tu l'utilise et qu'il n'y aura donc aucune diffrence entre les deux lignes suivantes


```

```

----------


## KlausGunther

Je n'avais pas vu a... Je vais adapter mon code avec "LoadArrayFromStrings" selon ta suggestion.

Voici la version modifie. J'ai remplac les deux mthodes LoadArrayFromMemoObject et LoadArrayFromMemoHandle en mthodes propres  TArrayObject, sans virtualisation.
Merci ! C'est beaucoup plus simple comme a !

A titre d'exemple, je charge OldPattern par LoadArrayFromStringsByHandle et NewPattern par LoadArrayFromStrings.

*EDIT*  29/01/2020  18;30

Correction d'un bug dans TBinaryAray.

----------


## KlausGunther

J'ai ajout des mthodes pour charger les tableaux par des chanes de caractres contenant une reprsentation hexa-dcimale des patterns, crant des TByteArray dans ce cas, et ceci indpendemment pour le critre  remplacer et pour le nouveau critre  insrer.

Dans le GUI du programme principal, sparment pour chacune des deux listes de critres, une ComboBox permet de choisir la reprsentation "string" ou "byte" (dfaut "string"). Le reste est automatique. Les critres concerns sont automatiquement convertis de ASCII en hexa et vice-versa.

Les critres affichs par dfaut sont  utiliser avec le petit fichier demo1.txt qui est fourni dans le ZIP.

----------

