Programmation Ruby/Types standards
Nous allons voir ici tous les types que nous pouvons considérer comme "standards", dans le sens où nous les retrouvons dans la plupart des langages, et que ceux-ci sont directement intégrés à l'interpréteur (built-in). Néanmoins il ne faut pas perdre de vue qu'il s'agit en réalité d'objets.
Pour rappel les méthodes dont le nom se termine par ! sont non pures : elles modifient l'objet.
Chaîne de caractères
modifierEn ruby les chaînes de caractères sont représentées par l'objet "String". En réalité cet objet contient et permet la manipulation d'un nombre indéfini d'octets, typiquement des caractères, nous pourrons néanmoins y stocker tout type de données binaires ou non.
Créer une chaîne de caractères
modifierEn ruby il existe une multitude de manières de créer une chaîne de caractères, par exemple en créant une instance de l'objet String :
maChaine = String.new("Une chaîne de caractères")
Mais le moyen le plus courant de créer une chaîne est de la placer entre simple quote (') ou entre double quote ("). Néanmoins ces deux moyens ne sont pas équivalents : en utilisant les doubles quotes ruby évaluera les expressions contenues entre #{ et }, ainsi que les caractères d'échappements.
i = 100 puts "la valeur de i est \n #{i}" => La valeur de i est 100 puts 'la valeur de i est \n #{i}' => la valeur de i est \n #{i}
Dans une chaîne de caractère \ a une valeur particulière, elle permet de placer un caractères d'échappements. Le caractère \ indique à ruby que le caractère suivant possède une valeur particulière : ainsi "\n" représente une nouvelle ligne. Les caractères d'échappements ne sont pas pris en compte avec une chaîne de caractères débutant par un simple quote, néanmoins nous pouvons l'utiliser pour indiquer à Ruby de considérer le simple quote ou le backslash suivant comme faisant partie de la chaîne :
puts 'un simple quote : \' qui ne ferme pas la chaîne, et ici un backslash : \\' => un simple quote : ' qui ne ferme pas la chaîne, et ici un backslash : \
Un autre moyen de créer une chaîne est d'utiliser %q ou %Q, qui équivalent respectivement au simple et au double quote. Néanmoins l'utilisation de %q ou %Q permet de définir le caractère d'ouverture et de fermeture de la chaîne :
%q!j'utilise le caractère \! pour ouvrir ou fermer la chaîne, ' et " peuvent ainsi être utilisés sans \ ! %q*je peux utiliser n'importe quel caractère non alpha-numérique qui n'est pas dans la chaîne elle même*
Si nous avons plusieurs lignes de texte à écrire nous pouvons utiliser les caractères << suivit d'un identifiant pour créer une chaîne ayant les mêmes propriétés qu'une chaîne entre double quote, ou les caractères <<- suivis d'un identifiant entre simple quote pour créer une chaîne de caractères ayant les mêmes propriétés qu'une chaîne entre simple quote :
i = 100 maChaine <<DEBUT une chaîne de caractères i vaut #{i} DEBUT => une chaîne de caractères i vaut 100 i = 100 maChaine <<-'DEBUT' une chaîne de caractères i vaut #{i} DEBUT => une chaîne de caractères i vaut #{i}
Le dernier moyen d'obtenir une chaîne de caractères est d'utiliser la méthode to_s que la plupart des objets implémentent, ainsi :
42.to_s => "42"
Comparaisons de chaînes
modifierLes chaînes de caractères peuvent être comparées comme indiqué dans le chapitre Expressions booléennes grâce aux méthodes <, <=, ==, >=, >
"abcdef" <=> "abcde" => 1 "abcdef" <=> "abcdef" => 0 "abcdef" <=> "abcdefg" => -1 "abcdef" <=> "ABCDEF" => 1 # Les caractères minuscules sont supérieurs aux caractères majuscules "abc" <=> "acc" => -1 "a" < "b" => true "a" < "a" => false "a" > "b" => false "a" > "a" => false "a" <= "b" => true "a" <= "a" => true "a" >= "b" => false "a" >= "a" => true "a" == "a" => true "a" == "b" => false "a" != "a" => false "a" != "b" => true
La méthode est équivalente à <=>, à part que la casse n'est pas comparée :
"abcdef".casecmp("ABCDEF") => 0
Manipulation de chaînes
modifierTaille d'une chaîne et index des caractères
modifierlength
modifierlength permet de connaître la taille d'une chaîne de caractères :
"Bonjour le monde".length => 16
index et rindex
modifierindex renvoie l'index de la première occurrence d'une sous chaîne dans la chaîne de caractères, renvoi nil si aucune occurrence n'a été trouvée :
"hello".index('e') => 1 "hello".index('lo') => 3 "hello".index('a') => nil
Si un entier est donné en second paramètre, celui-ci indique l'index où commencer la recherche.
"Bonjour le monde".index('o',7) => 12
Nous pouvons également utiliser une expression rationnelle.
rindex effectue le même travail à la différence près que la recherche se fait à partir de la fin de la chaîne de caractères :
"Bonjour le monde".rindex('o') => 12
Si le second paramètre est présent, la recherche commencera au caractère indiqué :
"Bonjour le monde".rindex('o',9) => 4
À noter que si le second paramètre est négatif, alors l'index est compté à partir de la fin de la chaîne :
"Bonjour le monde".rindex('o',-9) => 4 "Bonjour le monde".rindex('o',-2) => 12
Opérateurs sur les chaînes de caractères
modifier*
modifierL'opérateur de multiplication renvoie une chaîne de caractères contenant n fois la chaîne représentée par l'objet :
"Ho! " * 3 => Ho! Ho! Ho!
+
modifierL'opérateur d'addition permet de concaténer deux chaînes de caractères :
maChaine = "le Monde"
"Bonjour " + maChaine => Bonjour le Monde
[] et []=
modifierL'opérateur [] permet de récupérer un ou plusieurs caractères faisant partie d'une chaîne. Si un entier est passé en paramètre, l'opérateur renverra le code ASCII du caractère correspondant (le premier caractère est indexé par la valeur 0) :
maChaine = "Bonjour le monde" maChaine[3] => 106 # Correspond au code ASCII du 4e caractère (j)
Si deux entiers sont passés en paramètres, l'opérateur renverra une sous-chaîne commençant à l'index passé en premier paramètre et de longueur indiquée par le second élément :
maChaine[1,5] => onjou
On peut également indiquer un intervalle :
maChaine[1..6] => onjou
Il est à noter que si l'index est négatif, ruby compte à partir de la fin de la chaîne :
maChaine[-3,5] => nde
On peut également utiliser une expression rationnelle, nous verrons cela plus en détail dans le chapitre correspondant.
L'opérateur []= permet de changer le contenu d'une chaîne de caractères. L'utilisation est semblable à celle de [], à la différence que plutôt que de renvoyer un ensemble de caractères, l'opérateur modifiera la chaîne :
maChaine[3] = "V" puts maChaine => BonVour le monde
maChaine[8] = "tout " puts maChaine => Bonjour tout le monde
Si deux entiers sont passés en paramètres, ruby remplacera la chaîne commençant à l'index passé en première paramètre et d'une longueur passée en second paramètre :
maChaine[8,8] = "Roger" puts maChaine => Bonjour Roger maChaine[8..16] = "Roger" puts maChaine => Bonjour Roger
On peut directement utiliser une chaîne de caractères ou une expression rationnelle :
maChaine["Bonjour"] = "Hello" puts maChaine => Hello le monde
Formatage de chaîne
modifiersplit
modifiersplit permet de séparer les différents éléments d'une chaîne en fonction d'un ou plusieurs délimiteurs, par défaut ceux-ci sont les fins de ligne et les espaces (\s, \t, \r,\n et \r\n). La méthode renvoi un tableau contenant les différents éléments :
"Bonjour le monde".split => ["Bonjour", "le", "monde"] "B.o.n.j.o.u.r".split('.') => ["B","o","n","j","o","u","r"]
Si un entier est donné en paramètre, le tableau résultant n'aura comme nombre d'éléments la valeur de cet entier :
"B.o.n.j.o.u.r".split('.',3) => ["B","o","n.j.o.u.r"]
Nous pouvons également utiliser une expression rationnelle.
chomp, chomp!, chop et chop!
modifierchop et chop! permettent de supprimer le dernier caractère d'une chaîne, néanmoins si les deux derniers caractères sont "\r\n", les deux caractères sont supprimés :
"Bonjour\r\n".chop => "Bonjour" "Bonjour\n\r".chop => "Bonjour\n" "Bonjour\n".chop => "Bonjour" "Bonjour".chop => "Bonjou"
chomp et chomp! suppriment le dernier caractère seulement si celui-ci est un caractère de fin de ligne (soit "\r", "\n" et "\r\n") :
"Bonjour".chomp => "Bonjour" "Bonjour\n".chomp => "Bonjour" "Bonjour \n le monde".chomp => "Bonjour \n le monde"
Si une chaîne de caractères est donnée en paramètre, celle-ci est supprimée si elle est termine la chaîne :
"Bonjour".chomp("jour") => "Bon" "Bonjour\r\n".chomp("jour") => "Bonjour\r\n"
Pour rappel, les méthodes finissant par "!" sont des méthodes non pures : elles modifient l'objet appelant.
downcase, downcase!, upcase, upcase!, swapcase, swapcase!, capitalize et capitalize!
modifierdowncase et upcase permettent de passer respectivement tous les caractères en majuscules ou en minuscules.
"BonjOUr".downcase => "bonjour" "BonjOUr".upcase => "BONJOUR"
swapcase inverse la casse :
"BonjOUr".swapcase => "bONJouR"
capitalize ne met que le premier caractère en majuscule :
"bonjOUr".capitalize => "Bonjour"
%
modifierL'opérateur % permet de formater la chaîne de caractères. Le format utilisé est le même que celui de la fonction sprintf de ruby et de bien d'autres langages tel le C. Le format est décrit par le caractère % suivi d'un indicateur optionnel, un indicateur de taille, de précision et de type.
Les indicateurs de type :
Indicateur | Description |
b | données binaire |
c | caractère |
d ou i | nombre entier |
e | convertit un nombre entier sous sa forme exponentielle avec un chiffre avant la virgule, la précision indique le nombre de chiffres après la virgule (par défaut 6) |
E | comme e mais utilise le caractère majuscule E pour indiquer l'exposant |
f | nombre flottant, la précision indique le nombre de chiffres après la virgule |
g | comme e mais converti en nombre flottant |
G | comme E mais converti en nombre flottant |
o | nombre octal |
p | symbole |
s | chaîne de caractères, si une précision est donnée, alors elle indique le nombre de caractères |
u | nombre entier non signé (pas de signe) |
x | hexadécimal en utilisant les caractères minuscules (par exemple f) |
X | hexadécimal en utilisant les caractères majuscules (par exemple F) |
Format :
Indicateur | Types applicable | Description |
espace | bdeEfgGioxXu | Laisse un espace au début des nombres positifs |
# | bdeEfgGioxXu | Format alternatif, pour les types o, x, X et b préfixe respectivement le résultat par 0, 0x, 0X, et 0b |
+ | bdeEfgGioxXu | Ajoute un + au début des nombres positifs |
- | bdeEfgGioxXu | Ajoute un - au début des nombres négatifs |
0 | tous | Remplit le format avec des 0 plutôt que des espaces |
. | tous | Prend l'argument suivant comme taille pour aligner à droite s'il est positif. Si l'argument est négatif, aligne à gauche |
"%.3s" % 42424242 => "424"
Si plusieurs éléments doivent être formatés, il faut passer les paramètres dans un tableau :
"%d %04x" % [12.5, 42] => "12 002a"
unpack
modifierLa méthode unpack permet de décoder des chaînes de caractères (ou contenant des données binaires) en corrélation avec une chaîne de format.
Indicateur | Description | Type renvoyé |
A | Chaîne de caractères en supprimant les caractères vides (espace, tabulation...) | String |
a | Chaîne de caractères | String |
B | Extrait les bits de chaque caractère (bit de poids fort en premier) | String |
b | Extrait les bits de chaque caractère (bit de poids faible en premier) | String |
C | Extrait un caractère comme un entier non signé | Fixnum |
c | Extrait un caractère comme un entier signé | Fixnum |
d | Considère sizeof(double) caractères comme un double | Float |
E | Considère sizeof(double) caractères comme un double en little-endian | Float |
e | Considère sizeof(float) caractères comme un flottant en little-endian | Float |
f | Considère sizeof(float) caractères comme un flottant | Float |
G | Considère sizeof(double) caractères comme un double dans l'ordre réseau | Float |
g | Considère sizeof(float) caractères comme un flottant dans l'ordre réseau | Float |
H | Extrait le code hexadécimal de chaque caractère (bit de poids fort en premier) | String |
h | Extrait le code hexadécimal de chaque caractère (bit de poids faible en premier) | String |
I | Considère sizeof(int) caractères comme un entier non signé | Integer |
i | Considère sizeof(int) caractères comme un entier signé | Integer |
L | Considère 4 caractères consécutifs comme un entier long non signé | Integer |
i | Considère 4 caractères consécutifs comme un entier long signé | Integer |
M | Décode les chaînes "quoted printable" | String |
m | Décode les chaînes en Base64 | String |
N | Considère 4 caractères consécutifs comme un entier long non signé dans l'ordre réseau | Fixnum |
n | Considère 2 caractères consécutifs comme un entier court non signé dans l'ordre du réseau | Fixnum |
P | Considère sizeof(char *) comme un pointeur et renvoi la taille de la chaîne ainsi référencée | String |
P | Considère sizeof(char *) comme un pointeur sur une chaîne terminée par le caractère null (\0) | String |
S | Considère 2 caractères consécutifs comme un entier court non signé dans l'ordre natif du système | Fixnum |
s | Considère 2 caractères consécutifs comme un entier court signé dans l'ordre natif du système | Fixnum |
U | Extrait une chaîne encodée au format UTF8 comme des entiers non signés | Integer |
u | Extrait une chaîne encodée en UU | String |
V | Considère 4 caractères consécutifs comme un entier long non signé en "little endian" | Fixnum |
v | Considère 2 caractères consécutifs comme un entier court non signé en "little endian" | Fixnum |
X | Retourne en arrière d'un caractère | N/A |
x | Avance d'un caractère | N/A |
Z | Supprime les caractères null de fin | String |
@ | Se déplace du nombre donné en argument | N/A |
La chaîne de format se compose d'un nombre de directives à piocher dans le tableau précédent, facultativement suivi d'un nombre indiquant le nombre de fois qu'il faut répéter cette directive, un astérisque (*) correspondant a tous les éléments restant. Les directives s,S,i,I,l et L peuvent être suivis d'un underscore (_) indiquant de choisir le format natif du système.
Exemples :
"abc \0\0abc \0\0".unpack('A6Z6') => ["abc", "abc "] "abc \0\0".unpack('a3a3') => ["abc", " \000\000"] "aa".unpack('b8B8') => ["10000110", "01100001"] "aaa".unpack('h2H2c') => ["16", "61", 97] "\xfe\xff\xfe\xff".unpack('sS') => [-2, 65534] "now=20is".unpack('M*') => ["now is"] "whole".unpack('xax2aX2aX1aX2a') => ["h", "e", "l", "l", "o"]
Itérateurs
modifierLes itérateurs sont un mécanisme puissant de ruby, ils permettent de parcourir les éléments d'un objet. Nous verrons plus tard comment étendre facilement sa propre classe avec des itérateurs. Pour chaque type que nous allons voir, nous allons voir ses itérateurs. À l'heure actuelle considérons simplement un itérateur comme une méthode prenant un bloc pour paramètre (et d'ailleurs c'est ce que les itérateurs sont : de simples méthodes).
succ, succ! et upto
modifiersucc se contente de renvoyer l'élément succédant à la chaîne, en pratique succ incrémente le dernier caractère alphanumérique de la chaîne, si celui-ci a atteint sa limite, succ incrémentera l'avant-dernier caractère et ainsi de suite:
"abcd".succ => "abce" "THX1138".succ => "THX1139" "<<koala>>".succ => "<<koalb>>" "1999zzz".succ => "2000aaa"
upto itère à travers les valeurs successives d'une chaîne, jusqu'à arriver à la chaîne passée en paramètre. La méthode incrémente à partir de la dernière valeur alphanumérique de la chaîne :
"<<aa>>".upto("<<bb>>") do |i| puts i end => <<aa>> <<ab>> <<ac>> <<ad>> <<ae>> <<af>> <<ag>> <<ah>> <<ai>> <<aj>> <<ak>> <<al>> <<am>> <<an>> <<ao>> <<ap>> <<aq>> <<ar>> <<as>> <<at>> <<au>> <<av>> <<aw>> <<ax>> <<ay>> <<az>> <<ba>> <<bb>>
each_byte
modifiereach_byte permet d'itérer à travers la chaîne de caractères, octet par octet. La valeur qui sera envoyée au bloc sera le code ASCII (donc un entier) du caractère :
"bonjour".each_byte {|i| print i.to_s+" "} => 98 111 110 106 111 117 114
each
modifiereach permet d'itérer à travers chaque ligne contenue dans une String :
"H\nA\r\nL\n".each do |i| print i.succ end => IBM
Il est à noter que l'itérateur each est celui appelé par la construction for..in' :
for i in "H\nA\r\nL\r" print i.succ end => IBM
Valeur numérique
modifierEn ruby les valeurs numériques sont soit flottantes soit entières et sont de taille infinie (jusqu'à la limite de mémoire du système). Plus tôt dans le livre, nous avons indiqué qu'un type entier est de type Integer. En fait nous avons menti. Le type Integer permet en réalité de cacher le type réel de la valeur. En effet, les valeurs inférieures aux valeurs d'un entier sur le système (donc en général 32 ou 64 bits) sont en réalité de type Fixnum. Au delà, elles seront de types Bignum. En pratique la conversion est transparente pour le développeur :
i = 10 5.times do print i.class,"\n" i = i*i end => Fixnum Fixnum Fixnum Fixnum Bignum
Syntaxe
modifierEn ruby une valeur numérique peut s'écrire de différente forme, notamment en fonction de la base utilisée.
Classiquement, une valeur numérique peut s'écrire comme une suite de chiffres séparés éventuellement par des caractères de soulignement ( _) qui seront ignorés lors de l'interprétation. Une valeur négative est simplement préfixée par le signe moins (-) :
42 => 42 4_2 => 42 -42 => -42
On peut également travailler dans une autre base en préfixant la valeur numérique. Ainsi en préfixant avec 0 (zéro) on indique l'utilisation d'un nombre en base octale, 0x pour un nombre en hexadécimal et 0b pour un nombre en binaire :
0767 => 503 0xaabb => 43707 0b01101101 => 109
Utilisation
modifierUn objet correspondant à une valeur numérique s'instancie simplement en écrivant cette valeur :
4 => 4 4.class => Fixnum
Certains objets, comme l'objet String, possèdent une méthode to_i qui renvoie si possible une valeur entière, et to_f qui renvoi si possible un flottant :
" 58_87".to_i => 5887
Si la chaîne contient des éléments non numériques, à l'exception du caractère de soulignement ou du signe moins, la valeur renvoyée sera celle de la première valeur numérique trouvée et précédant les autres caractères :
"toto".to_i => 0 "to87to".to_i => 0 "87to".to_i => 87
"Opérateurs" arithmétiques
modifierAttention : En Ruby les opérateurs n'existent pas, ce sont des méthodes inclusent dans l'objet Ruby père Object. On parle donc ici d'"opérateur" par analogie avec les langages orientés objet et procéduraux.
il faut bien comprendre que :
2 + 4
équivaut à
2.+(4)
tel que
objet1 = 2 objet2 = 4 objet1.+(objet2) => 6
Pour simplifier la lecture, on accordera l'usage de cet abus de langage dans le reste du document pour faciliter le passage d'un autre langage vers Ruby
+
modifierL'opérateur + permet d'additionner 2 valeurs numériques :
2+2 => 4 "3+4".to_i => 3
-
modifierL'opérateur - permet de soustraire une valeur numérique à une autre :
42-10 => 32 2-10 => -8
*
modifierL'opérateur * permet de multiplier 2 valeurs numériques :
42*2 => 84
/
modifierL'opérateur / permet de diviser une valeur numérique par une autre :
9/3 => 3
ATTENTION: Le type renvoyé est du type des opérandes, ainsi si la division n'est pas entière, seul le dividende est renvoyé:
9/4 => 2
par contre, si nous utilisons au moins un flottant, le type renvoyé sera de type flottant :
9.0/4 => 2.25
Une division par 0 lève une exception (nous verrons les exceptions plus tard, il suffit de considérer à l'heure actuelle qu'il s'agit d'une erreur) et interrompt le cours du programme si celle-ci n'est pas interceptée :
9/0 => ZeroDivisionError: divided by 0
**
modifierL'opérateur ** permet d'augmenter une valeur numérique à la puissance indiquée en paramètre :
9**2 => 81 9**0 => 1
%
modifierL'opérateur % (modulo) permet de connaître le reste d'une division :
100%30 => 10
Itérateurs
modifierLa classe Integer propose également certains itérateurs, comme pour tout autre itérateur, ceux-ci prennent un ou plusieurs paramètres ainsi qu'un bloc de code.
succ
modifiersucc permet de récupérer la valeur numérique suivante :
8.succ => 9
times
modifiertimes permet de créer une boucle allant de 0 à la valeur de l'objet :
5.times do |val| print val.to_s+'..' end => 0..1..2..3..4..
upto et downto
modifierupto et downto permettent respectivement d'itérer à partir de la valeur de l'objet jusqu'à la valeur passée en paramètre, respectivement en incrémentant ou en décrémentant :
5.upto(8) do |i| print i.to_s+'..' end => 5..6..7..8.. 8.downto(5) do |i| print i.to_s+'..' end => 8..7..6..5.. 5.downto(8) do |i| print i.to_s+'..' end => 5
step
modifierstep ressemble à upto et downto à part que l'on peut préciser le pas :
5.step(48, 5) do |i| print i.to_s+'..' end #ici le second paramètre correspond au pas => 5..10..15..20..25..30..35..40..45..
Expression rationnelle
modifierLes expressions rationnelles (parfois nommées à tort expressions régulières) sont un mécanisme puissant mais qui peut être complexe. Elles permettent des recherches dans une chaîne de caractères selon des critères ou un modèle de recherche précis. Ceci permet la sélection d'une sous chaîne de caractères, ou la manipulation des chaînes ainsi trouvées (typiquement une substitution).
Ruby propose une classe pour l'utilisation des expressions rationnelles, les développeurs Perl seront heureux car son utilisation en Ruby est quasi-identique (voir Catégorie:Expressions rationnelles).