• Aucun résultat trouvé

Les chaînes de caractères

3 Classes NET d'usage courant

3.2 Les chaînes de caractères

3.2.1

La classe System.String

1

2 3

4

La classe System.String est identique au type simple string. Elle présente de nombreuses propriétés et méthodes. En voici quelques-unes :

public int Length { get; } nombre de caractères de la chaîne

public bool EndsWith(string value) rend vrai si la chaîne se termine par value

public bool StartsWith(string value) rend vrai si la chaîne commence par value

public virtual bool Equals(object obj) rend vrai si la chaînes est égale à obj - équivalent chaîne==obj

public int IndexOf(string value, int startIndex) rend la première position dans la chaîne de la chaîne value - la recherche commence à partir du caractère n° startIndex

public int IndexOf(char value, int startIndex) idem mais pour le caractère value

public string Insert(int startIndex, string value) insère la chaîne value dans chaîne en position

startIndex

public static string Join(string separator,

string[] value) méthode de classe - rend une chaîne de caractères, résultat de la concaténation des valeurs du tableau

value avec le séparateur separator

public int LastIndexOf(char value, int startIndex,

int count)

public int LastIndexOf(string value, int

startIndex, int count)

idem indexOf mais rend la dernière position au lieu de la première

public string Replace(char oldChar, char newChar) rend une chaîne copie de la chaîne courante où le caractère oldChar a été remplacé par le caractère

newChar

public string[] Split(char[] separator) la chaîne est vue comme une suite de champs séparés par les caractères présents dans le tableau

separator. Le résultat est le tableau de ces champs

public string Substring(int startIndex, int length) sous-chaîne de la chaîne courante commençant à la position startIndex et ayant length caractères public string ToLower() rend la chaîne courante en minuscules

public string ToUpper() rend la chaîne courante en majuscules

public string Trim() rend la chaîne courante débarrassée de ses espaces de début et fin

On notera un point important : lorsqu'une méthode rend une chaîne de caractères, celle-ci est une chaîne différente de la chaîne sur laquelle a été appliquée la méthode. Ainsi S1.Trim() rend une chaîne S2, et S1 et S2 sont deux chaînes différentes.

Une chaîne C peut être considérée comme un tableau de caractères. Ainsi  C[i] est le caractère i de C

C.Length est le nombre de caractères de C

Considérons l'exemple suivant : 1. using System; 2.

3. namespace Chap3 { 4. class Program {

5. static void Main(string[] args) {

6. string uneChaine = "l'oiseau vole au-dessus des nuages"; 7. affiche("uneChaine=" + uneChaine);

8. affiche("uneChaine.Length=" + uneChaine.Length); 9. affiche("chaine[10]=" + uneChaine[10]);

10. affiche("uneChaine.IndexOf(\"vole\")=" + uneChaine.IndexOf("vole")); 11. affiche("uneChaine.IndexOf(\"x\")=" + uneChaine.IndexOf("x")); 12. affiche("uneChaine.LastIndexOf('a')=" + uneChaine.LastIndexOf('a')); 13. affiche("uneChaine.LastIndexOf('x')=" + uneChaine.LastIndexOf('x')); 14. affiche("uneChaine.Substring(4,7)=" + uneChaine.Substring(4, 7)); 15. affiche("uneChaine.ToUpper()=" + uneChaine.ToUpper());

16. affiche("uneChaine.ToLower()=" + uneChaine.ToLower());

17. affiche("uneChaine.Replace('a','A')=" + uneChaine.Replace('a', 'A')); 18. string[] champs = uneChaine.Split(null);

19. for (int i = 0; i < champs.Length; i++) {

20. affiche("champs[" + i + "]=[" + champs[i] + "]");

21. }//for

23. affiche("(\" abc \").Trim()=[" + " abc ".Trim() + "]"); 24. }//Main

25.

26. public static void affiche(string msg) { 27. // affiche msg

28. Console.WriteLine(msg);

29. }//affiche 30. }//classe 31. }//namespace

L'exécution donne les résultats suivants :

1. uneChaine=l'oiseau vole au-dessus des nuages 2. uneChaine.Length=34 3. chaine[10]=o 4. uneChaine.IndexOf("vole")=9 5. uneChaine.IndexOf("x")=-1 6. uneChaine.LastIndexOf('a')=30 7. uneChaine.LastIndexOf('x')=-1 8. uneChaine.Substring(4,7)=seau vo

9. uneChaine.ToUpper()=L'OISEAU VOLE AU-DESSUS DES NUAGES 10. uneChaine.ToLower()=l'oiseau vole au-dessus des nuages 11. uneChaine.Replace('a','A')=l'oiseAu vole Au-dessus des nuAges 12. champs[0]=[l'oiseau] 13. champs[1]=[vole] 14. champs[2]=[au-dessus] 15. champs[3]=[des] 16. champs[4]=[nuages] 17. Join(":",champs)=l'oiseau:vole:au-dessus:des:nuages 18. (" abc ").Trim()=[abc]

Considérons un nouvel exemple : 1. using System; 2.

3. namespace Chap3 { 4. class Program {

5. static void Main(string[] args) { 6. // la ligne à analyser

7. string ligne = "un:deux::trois:"; 8. // les séparateurs de champs

9. char[] séparateurs = new char[] { ':' }; 10. // split

11. string[] champs = ligne.Split(séparateurs); 12. for (int i = 0; i < champs.Length; i++) {

13. Console.WriteLine("Champs[" + i + "]=" + champs[i]);

14. }

15. // join

16. Console.WriteLine("join=[" + System.String.Join(":", champs) + "]");

17. }

18. } 19. }

et les résultats d'exécution : 1. Champs[0]=un 2. Champs[1]=deux 3. Champs[2]= 4. Champs[3]=trois 5. Champs[4]= 6. join=[un:deux::trois:]

La méthode Split de la classe String permet de mettre dans un tableau des éléments d'une chaîne de caractères. La définition de la méthode Split utilisée ici est la suivante :

public string[] Split(char[] separator);

separator tableau de caractères. Ces caractères représentent les caractères utilisés pour séparer les champs de la chaîne de caractères. Ainsi si la chaîne est "champ1, champ2, champ3" on pourra utiliser separator=new char[] {','}. Si le séparateur est une suite d'espaces on utilisera separator=null.

résultat tableau de chaînes de caractères où chaque élément du tableau est un champ de la chaîne. La méthode Join est une méthode statique de la classe String :

public static string Join(string separator, string[] value); value tableau de chaînes de caractères

separator une chaîne de caractères qui servira de séparateur de champs

résultat une chaîne de caractères formée de la concaténation des éléments du tableau value séparés par la chaîne separator.

3.2.2

La classe System.Text.StringBuilder

Précédemment, nous avons dit que les méthodes de la classe String qui s'appliquaient à une chaîne de caractères S1 rendait une autre chaîne S2. La classe System.Text.StringBuilder permet de manipuler S1 sans avoir à créer une chaîne S2. Cela améliore les performances en évitant la multiplication de chaînes à durée de vie très limitée.

La classe admet divers constructeurs :

StringBuilder() constructeur par défaut

StringBuilder(String value) construction et initialisation avec value

StringBuilder(String value, int capacité) construction et initialisation avec value avec une taille de bloc de capacité caractères.

Un objet StringBuilder travaille avec des blocs de capacité caractères pour stocker la chaîne sous-jacente. Par défaut capacité vaut 16. Le 3ième constructeur ci-dessus permet de préciser la capacité des blocs. Le nombre de blocs de capacité caractères nécessaire pour stocker une chaîne S est ajusté automatiquement par la classe StringBuilder. Il existe des constructeurs pour fixer le nombre maximal de caractères dans un objet StringBuilder. Par défaut, cette capacité maximale est 2 147 483 647.

Voici un exemple illustrant cette notion de capacité : 1. using System.Text;

2. using System; 3. namespace Chap3 { 4. class Program {

5. static void Main(string[] args) {

6. // str

7. StringBuilder str = new StringBuilder("test");

8. Console.WriteLine("taille={0}, capacité={1}", str.Length, str.Capacity); 9. for (int i = 0; i < 10; i++) {

10. str.Append("test");

11. Console.WriteLine("taille={0}, capacité={1}", str.Length, str.Capacity);

12. }

13. // str2

14. StringBuilder str2 = new StringBuilder("test",10);

15. Console.WriteLine("taille={0}, capacité={1}", str2.Length, str2.Capacity); 16. for (int i = 0; i < 10; i++) {

17. str2.Append("test");

18. Console.WriteLine("taille={0}, capacité={1}", str2.Length, str2.Capacity);

19. }

20. }

21. } 22. }

ligne 7 : création d'un objet StringBuilder avec une taille de bloc de 16 caractères

ligne 8 : str.Length est le nombre actuel de caractères de la chaîne str. str.Capacity est le nombre de caractères que peut stocker la chaîne str actuelle avant réallocation d'un nouveau bloc.

ligne 10 : str.Append(String S) permet de concaténer la chaîne S de type String à la chaîne str de type StringBuilder.ligne 14 : création d'un objet StringBuilder avec une capacité de bloc de 10 caractères

Le résultat de l'exécution : 1. taille=4, capacité=16 2. taille=8, capacité=16 3. taille=12, capacité=16 4. taille=16, capacité=16 5. taille=20, capacité=32 6. taille=24, capacité=32 7. taille=28, capacité=32 8. taille=32, capacité=32 9. taille=36, capacité=64 10. taille=40, capacité=64 11. taille=44, capacité=64 12. taille=4, capacité=10 13. taille=8, capacité=10 14. taille=12, capacité=20 15. taille=16, capacité=20 16. taille=20, capacité=20 17. taille=24, capacité=40 18. taille=28, capacité=40 19. taille=32, capacité=40 20. taille=36, capacité=40 21. taille=40, capacité=40 22. taille=44, capacité=80

Ces résultats montrent que la classe suit un algorithme qui lui est propre pour allouer de nouveaux blocs lorsque sa capacité est insuffisante :

• lignes 4-5 : augmentation de la capacité de 16 caractères

• lignes 8-9 : augmentation de la capacité de 32 caractères alors que 16 auraient suffi. Voici quelques-unes des méthodes de la classe :

public StringBuilder Append(string value) ajoute la chaîne value à l'objet StringBuilder. Rend l'objet StringBuilder. Cette méthode est surchargée pour admettre différents types pour value : byte, int, float, double, decimal, ...

public StringBuilder Insert(int index, string

value) insère value à la position index. Cette méthode est surchargée comme la précédente pour accepter différents types pour value.

public StringBuilder Remove(int index, int length) supprime length caractères à partir de la position

index.

public StringBuilder Replace(string oldValue,

string newValue) remplace dans StringBuilder, la chaîne oldValue par la chaîne newValue. Il existe une version surchargée (char oldChar, char newChar).

public String ToString() convertit l'objet StringBuilder en un objet de type String. Voici un exemple : 1. using System.Text; 2. using System; 3. namespace Chap3 { 4. class Program {

5. static void Main(string[] args) {

7. StringBuilder str3 = new StringBuilder("test");

8. Console.WriteLine(str3.Append("abCD").Insert(2, "xyZT").Remove(0, 2).Replace("xy", "XY"));

9. } 10. } 11. } et ses résultats : XYZTstabCD

3.3 Les tableaux

Les tableaux dérivent de la classe Array :

La classe Array possède diverses méthodes pour trier un tableau, rechercher un élément dans un tableau, redimensionner un tableau, ... Nous présentons certaines propriétés et méthodes de cette classe. Elles sont quasiment toutes surchargées, c.a.d. qu'elles existent en différentes variantes. Tout tableau en hérite.

Propriétés

public int Length {get;} nombre total d'éléments du tableau, quelque soit son nombre de dimensions

public int Rank {get;} nombre total de dimensions du tableau

Méthodes

public static int BinarySearch<T>(T[] tableau,T

value) rend la position de value dans tableau.

public static int BinarySearch<T>(T[] tableau,int

index, int length, T value) idem mais cherche dans tableau à partir de la position index et sur length éléments

public static void Clear(Array tableau, int index,

int length) met les length éléments de tableau commençant au n° index à 0 si numériques, false si booléens, null si

références

public static void Copy(Array source, Array

destination, int length) copie length éléments de source dans destination

public int GetLength(int i) nombre d'éléments de la dimension n° i du tableau

public int GetLowerBound(int i) indice du 1er élément de la dimension n° i

public int GetUpperBound(int i) indice du dernier élément de la dimension n° i

public static int IndexOf<T>(T[] tableau, T valeur) rend la position de valeur dans tableau ou -1 si valeur n'est pas trouvée.

public static void Resize<T>(ref T[] tableau, int

n) redimensionne tableau à n éléments. Les éléments déjà présents sont conservés.

public static void Sort<T>(T[] tableau,

Le programme suivant illustre l'utilisation de certaines méthodes de la classe Array : 1. using System; 2. 3. namespace Chap3 { 4. class Program { 5. // type de recherche

6. enum TypeRecherche { linéaire, dichotomique }; 7.

8. // méthode principale

9. static void Main(string[] args) {

10. // lecture des éléments d'un tableau tapés au clavier 11. double[] éléments;

12. Saisie(out éléments);

13. // affichage tableau non trié

14. Affiche("Tableau non trié", éléments);

15. // Recherche linéaire dans le tableau non trié 16. Recherche(éléments, TypeRecherche.linéaire); 17. // tri du tableau

18. Array.Sort(éléments);

19. // affichage tableau trié

20. Affiche("Tableau trié", éléments);

21. // Recherche dichotomique dans le tableau trié 22. Recherche(éléments, TypeRecherche.dichotomique);

23. }

24.

25. // saisie des valeurs du tableau éléments

26. // éléments : référence sur tableau créé par la méthode 27. static void Saisie(out double[] éléments) {

28. bool terminé = false; 29. string réponse; 30. bool erreur; 31. double élément = 0; 32. int i = 0;

33. // au départ, le tableau n'existe pas 34. éléments = null;

35. // boucle de saisie des éléments du tableau 36. while (!terminé) {

37. // question

38. Console.Write("Elément (réel) " + i + " du tableau (rien pour terminer) : "); 39. // lecture de la réponse

40. réponse = Console.ReadLine().Trim(); 41. // fin de saisie si chaîne vide 42. if (réponse.Equals(""))

43. break;

44. // vérification saisie

45. try {

46. élément = Double.Parse(réponse); 47. erreur = false;

48. } catch {

49. Console.Error.WriteLine("Saisie incorrecte, recommencez");

50. erreur = true;

51. }//try-catch

52. // si pas d'erreur 53. if (!erreur) {

54. // un élément de plus dans le tableau

55. i += 1;

56. // redimensionnement tableau pour accueillir le nouvel élément

57. Array.Resize(ref éléments, i);

58. // insertion nouvel élément 59. éléments[i - 1] = élément;

60. }

61. }//while

62. }

63.

64. // méthode générique pour afficher les éléments d'un tableau 65. static void Affiche<T>(string texte, T[] éléments) {

66. Console.WriteLine(texte.PadRight(50, '-')); 67. foreach (T élément in éléments) {

68. Console.WriteLine(élément);

69. }

70. }

71.

72. // recherche d'un élément dans le tableau 73. // éléments : tableau de réels

75. static void Recherche(double[] éléments, TypeRecherche type) { 76. // Recherche

77. bool terminé = false; 78. string réponse = null; 79. double élément = 0; 80. bool erreur = false; 81. int i = 0;

82. while (!terminé) {

83. // question

84. Console.WriteLine("Elément cherché (rien pour arrêter) : "); 85. // lecture-vérification réponse

86. réponse = Console.ReadLine().Trim();

87. // fini ?

88. if (réponse.Equals(""))

89. break;

90. // vérification

91. try {

92. élément = Double.Parse(réponse); 93. erreur = false;

94. } catch {

95. Console.WriteLine("Erreur, recommencez...");

96. erreur = true;

97. }//try-catch

98. // si pas d'erreur 99. if (!erreur) {

100. // on cherche l'élément dans le tableau 101. if (type == TypeRecherche.dichotomique) 102. // recherche dichotomique

103. i = Array.BinarySearch(éléments, élément);

104. else

105. // recherche linéaire

106. i = Array.IndexOf(éléments, élément);

107. // Affichage réponse 108. if (i >= 0)

109. Console.WriteLine("Trouvé en position " + i);

110. else

111. Console.WriteLine("Pas dans le tableau");

112. }//if

113. }//while 114. }

115. } 116.}

lignes 27-62 : la méthode Saisie saisit les éléments d'un tableau éléments tapés au clavier. Comme on ne peut dimensionner le tableau à priori (on ne connaît pas sa taille finale), on est obligés de le redimensionner à chaque nouvel élément (ligne 57). Un algorithme plus efficace aurait été d'allouer de la place au tableau par groupe de N éléments. Un tableau n'est cependant pas fait pour être redimensionné . Ce cas là est mieux traité avec une liste (ArrayList, List<T>).

lignes 75-113 : la méthode Recherche permet de rechercher dans le tabeau éléments, un élément tapé au clavier. Le mode de recherche est différent selon que le tableau est trié ou non. Pour un tableau non trié, on fait une recherche linéaire avec la méthode IndexOf de la ligne 106. Pour un tableau trié, on fait une recherche dichotomique avec la méthode BinarySearch de la ligne 103.

ligne 18 : on trie le tableau éléments. On utilise ici, une variante de Sort qui n'a qu'un paramètre : le tableau à trier. La relation d'ordre utilisée pour comparer les éléments du tableau est alors celle implicite de ces éléments. Ici, les éléments sont numériques. C'est l'ordre naturel des nombres qui est utilisé.

Les résultats écran sont les suivants :

1. Elément (réel) 0 du tableau (rien pour terminer) : 3,6 2. Elément (réel) 1 du tableau (rien pour terminer) : 7,4 3. Elément (réel) 2 du tableau (rien pour terminer) : -1,5 4. Elément (réel) 3 du tableau (rien pour terminer) : -7 5. Elément (réel) 4 du tableau (rien pour terminer) : 6. Tableau non trié--- 7. 3,6

8. 7,4 9. -1,5 10. -7

11. Elément cherché (rien pour arrêter) : 12. 7,4

13. Trouvé en position 1

14. Elément cherché (rien pour arrêter) : 15. 0

16. Pas dans le tableau

18. 19. Tableau trié--- 20. -7 21. -1,5 22. 3,6 23. 7,4

24. Elément cherché (rien pour arrêter) : 25. 7,4

26. Trouvé en position 3

27. Elément cherché (rien pour arrêter) : 28. 0

29. Pas dans le tableau

30. Elément cherché (rien pour arrêter) :