Bibliothèque string
La bibliothèque string fournit les opérations de manipulation de chaînes : sous-chaînes, casse,
recherche/remplacement par motif (« pattern », façon Lua — pas des expressions régulières),
formatage façon printf, et (dé)sérialisation binaire.
Toute valeur chaîne possède une métatable qui redirige l'indexation vers cette bibliothèque, ce qui permet la notation « méthode » en plus de la notation classique :
local s = "Hello, World!"
print(s:upper()) -- équivalent à string.upper(s)
print(string.len(s))
Sauf mention contraire, les positions (i, j, pos, ...) sont 1-based, comme partout ailleurs
dans YScript. Une position négative compte depuis la fin de la chaîne (-1 = dernier caractère).
Vue d'ensemble
| Fonction | Description |
|---|---|
string.byte(s [, i [, j]]) |
Codes numériques des caractères de s entre i et j |
string.char(···) |
Construit une chaîne à partir de codes numériques |
string.dump(function [, strip]) |
Sérialise une fonction en bytecode précompilé |
string.find(s, pattern [, init [, plain]]) |
Cherche un motif, retourne les positions (et captures) |
string.format(formatstring, ···) |
Formatage façon printf |
string.fromencoding(s, encoding) |
Décode une chaîne « binaire » (octets) en texte selon encoding |
string.gmatch(s, pattern [, init]) |
Itérateur sur toutes les occurrences d'un motif |
string.gsub(s, pattern, repl [, n]) |
Remplace les occurrences d'un motif |
string.len(s) |
Longueur de s |
string.lower(s) |
Convertit en minuscules |
string.match(s, pattern [, init]) |
Cherche un motif, retourne ses captures |
string.netformat(formatstring, ···) |
Formatage façon .NET ("{0}", "{1:F2}", ...) |
string.pack(fmt, ···) |
Sérialise des valeurs en chaîne binaire |
string.packsize(fmt) |
Taille en octets qu'occuperait string.pack(fmt, ···) |
string.rep(s, n [, sep]) |
Répète s n fois, séparées par sep |
string.reverse(s) |
Inverse l'ordre des caractères |
string.sub(s, i [, j]) |
Sous-chaîne de s entre i et j |
string.toencoding(s, encoding) |
Encode un texte en chaîne « binaire » (octets) selon encoding |
string.ucodepoint(s [, i [, j]]) |
Points de code Unicode des caractères de s entre i et j |
string.ucodes(s) |
Itérateur position, point de code sur les caractères de s |
string.ulen(s [, i [, j]]) |
Nombre de caractères de s (points de code, pas d'unités UTF-16) |
string.uoffset(s, n [, i]) |
Position de début du n-ième caractère à partir de i |
string.unpack(fmt, data [, pos]) |
Désérialise une chaîne binaire |
string.upper(s) |
Convertit en majuscules |
string.len(s)
Retourne la longueur de s, en caractères. Équivalent à l'opérateur #s.
string.sub(s, i [, j])
Retourne la sous-chaîne de s allant de la position i à la position j (incluses). j vaut
-1 par défaut (jusqu'à la fin de s). Les positions négatives comptent depuis la fin ; les
positions hors bornes sont silencieusement ramenées dans [1, #s]. Si, après ajustement, i > j,
retourne la chaîne vide.
print(("Hello"):sub(2, 4)) --> ell
print(("Hello"):sub(-3)) --> llo
string.upper(s) / string.lower(s)
Retournent s converti en majuscules / minuscules, selon la culture du script.
string.rep(s, n [, sep])
Retourne s répété n fois, chaque occurrence séparée par sep (chaîne vide par défaut). Si
n <= 0, retourne la chaîne vide. Une erreur est levée si la chaîne résultante dépasserait la
taille maximale représentable.
string.reverse(s)
Retourne s avec ses caractères dans l'ordre inverse.
string.byte(s [, i [, j]])
Retourne, comme plusieurs valeurs, les codes numériques des caractères de s de la position i
(défaut 1) à la position j (défaut i). Ne retourne aucune valeur si l'intervalle est vide
après ajustement.
print(string.byte("A")) --> 65
print(string.byte("ABC", 1, 3)) --> 65 66 67
string.char(···)
Inverse de string.byte : reçoit zéro ou plusieurs codes numériques et retourne la chaîne formée
de ces caractères. Chaque code doit être compris entre 0 et 0x10FFFF (dernier point de code
Unicode valide) :
- entre
0et65535, le code est ajouté tel quel comme une unité UTF-16 brute — y compris une moitié de paire de substitution isolée, pour composer manuellement une paire à travers deux arguments consécutifs (string.char(0xD83D, 0xDE00)) ; - au-delà de
65535, le code est un point de code complet, encodé automatiquement comme une paire de substitution (string.char(0x1F600)produit directement 😀, en une seule unité logique).
print(string.char(72, 101, 108, 108, 111)) --> Hello
print(string.char(0x1F600)) --> 😀
Unicode : caractères vs unités UTF-16
Les chaînes YScript sont du texte Unicode natif .NET (UTF-16) — voir
Types et valeurs. La plupart des fonctions de cette bibliothèque
(len, sub, byte, ...) raisonnent en unités de code UTF-16, pas en caractères Unicode : un
caractère hors du plan de base (« BMP » — la plupart des emojis, certains sinogrammes rares, ...)
occupe deux unités (une « paire de substitution »), donc #s compte 2 pour un seul emoji, et
indexer au mauvais endroit avec string.sub/string.byte peut couper une paire en deux.
Les quatre fonctions suivantes raisonnent en points de code (un point de code = un caractère
Unicode, quelle que soit sa largeur en UTF-16) — dans l'esprit de la bibliothèque utf8 de Lua,
mais adaptées : YScript n'a pas besoin de décoder de l'UTF-8 stocké dans une chaîne d'octets
puisque ses chaînes sont déjà du texte Unicode ; les positions qu'elles acceptent/retournent
restent des indices UTF-16 (comme partout ailleurs dans cette bibliothèque), pas des offsets
d'octets UTF-8.
string.ucodepoint(s [, i [, j]])
Retourne, comme plusieurs valeurs, le point de code Unicode de chaque caractère de s dont le
début se situe entre les positions i (défaut 1) et j (défaut i) — un point de code hors BMP
compte pour une seule valeur de retour, même s'il occupe deux positions UTF-16.
local s = "a" .. string.char(0x1F600) .. "b"
print(string.ucodepoint(s, 1, #s)) --> 97 128512 98
string.ulen(s [, i [, j]])
Comme string.len, mais compte les caractères (points de code), pas les unités UTF-16 — j vaut
-1 par défaut (jusqu'à la fin de s), comme string.sub. Retourne nil plus la position fautive
si s contient une moitié de paire de substitution isolée, plutôt que de lever une erreur.
local s = "a" .. string.char(0x1F600) .. "b"
print(#s, string.ulen(s)) --> 4 3
string.uoffset(s, n [, i])
Retourne la position de début du n-ième caractère à partir de la position i : n = 0 retourne
le début du caractère qui contient i (utile pour se replacer sur une frontière de caractère après
une position calculée à la main) ; n > 0 avance de n - 1 caractères puis retourne cette
position ; n < 0 recule de |n| caractères. i vaut 1 par défaut si n >= 0, #s + 1 sinon.
Retourne nil si ce déplacement dépasse une extrémité de s.
local s = "a" .. string.char(0x1F600) .. "b"
print(string.uoffset(s, 2)) --> 2 (début de l'emoji)
print(string.uoffset(s, 0, 3)) --> 2 (position 3 tombe au milieu de l'emoji)
string.ucodes(s)
Itérateur utilisable dans un for générique, retournant à chaque étape la position (1-based, index
UTF-16) et le point de code du caractère suivant de s — un passage par caractère, pas par unité
UTF-16, donc une paire de substitution n'est visitée qu'une fois. Lève une erreur si s contient
une moitié de paire de substitution isolée.
local s = "a" .. string.char(0x1F600) .. "b"
for p, c in string.ucodes(s) do
print(p, c)
end
--> 1 97
--> 2 128512
--> 4 98
string.toencoding(s, encoding) / string.fromencoding(s, encoding)
Conversions entre un texte YScript normal et une représentation « binaire » où chaque caractère de
la chaîne vaut un octet (0-255) — la même convention que le mode binaire de io et que
string.pack/string.dump.
toencoding(s, encoding)encodesselonencodinget retourne la chaîne binaire résultante.fromencoding(s, encoding)fait l'inverse : décode une chaîne binaire (typiquement produite partoencoding, ou lue d'un fichier ouvert en mode binaire) en texte, en interprétant ses octets selonencoding. Lève une erreur sisn'est pas une chaîne binaire valide (caractères hors0-255), ou si le décodage échoue pour l'encodage demandé.
encoding accepte les mêmes noms/codepages que le 3ᵉ argument de io.open (y compris le
pseudo-nom "binary").
string.find(s, pattern [, init [, plain]])
Cherche la première occurrence de pattern dans s, à partir de la position init (défaut 1).
En cas de succès, retourne la position de début et de fin de l'occurrence, suivies des captures
éventuelles du motif (voir « Motifs » plus bas). Retourne nil si aucune occurrence n'est trouvée.
Si plain est vrai, ou si pattern ne contient aucun caractère spécial de motif, la recherche se
fait en texte brut (sous-chaîne exacte), sans interpréter pattern comme un motif — plus rapide
et sans surprise pour une recherche littérale.
print(string.find("hello world", "wor")) --> 7 9
print(string.find("hello world", "o", 6)) --> 8 8
print(string.find("2024-01-15", "(%d+)-(%d+)")) --> 1 7 2024 01
string.match(s, pattern [, init])
Comme string.find, mais retourne directement les captures de la première occurrence (ou la
chaîne entière si le motif n'a pas de capture explicite), sans les positions de début/fin. Retourne
nil si aucune occurrence n'est trouvée.
print(string.match("hello world", "%a+")) --> hello
print(string.match("key = value", "(%w+)%s*=%s*(%w+)")) --> key value
string.gmatch(s, pattern [, init])
Retourne une fonction itératrice qui, à chaque appel, retourne les captures de l'occurrence
suivante de pattern dans s (à partir de init, défaut 1), jusqu'à épuisement.
for word in string.gmatch("the quick brown fox", "%a+") do
print(word)
end
string.gsub(s, pattern, repl [, n])
Remplace dans s les occurrences de pattern par repl, au maximum n fois (toutes par défaut).
Retourne la chaîne résultante suivie du nombre de remplacements effectués. repl peut être :
- une chaîne (ou un nombre) : gabarit de remplacement où
%0désigne l'occurrence entière,%1-%9la capture correspondante, et%%un%littéral ; - une table : chaque occurrence est remplacée par
repl[capture](la première capture, ou l'occurrence entière s'il n'y en a pas) — si cette valeur estnil/false, l'occurrence d'origine est conservée ; - une fonction : appelée avec les captures de l'occurrence (ou l'occurrence entière) en
arguments ; sa valeur de retour remplace l'occurrence selon la même règle que pour une table
(
nil/falseconserve l'occurrence d'origine, sinon la valeur doit être convertible en chaîne).
print(string.gsub("hello world", "o", "0")) --> hell0 w0rld 2
print(string.gsub("hello world", "%w+", string.upper)) --> HELLO WORLD 2
print(string.gsub("$name is $age", "%$(%w+)", { name = "Ana", age = "30" }))
--> Ana is 30 2
Motifs (« patterns »)
find, match, gmatch et gsub interprètent pattern avec le langage de motifs façon Lua — un
sous-ensemble volontairement limité par rapport aux expressions régulières, mais suffisant pour
l'essentiel des besoins de traitement de texte, et sans leurs pièges de performance.
Classes de caractères (un caractère quelconque parmi une catégorie) :
| Classe | Signifie | Classe | Signifie (négation, majuscule) |
|---|---|---|---|
. |
N'importe quel caractère | ||
%a |
Lettre | %A |
Tout sauf une lettre |
%d |
Chiffre | %D |
Tout sauf un chiffre |
%l |
Minuscule | %L |
Tout sauf une minuscule |
%u |
Majuscule | %U |
Tout sauf une majuscule |
%s |
Espace (espace, tab, saut de ligne) | %S |
Tout sauf un espace |
%w |
Alphanumérique | %W |
Tout sauf alphanumérique |
%p |
Ponctuation | %P |
Tout sauf ponctuation |
%c |
Caractère de contrôle | %C |
Tout sauf un caractère de contrôle |
%x |
Chiffre hexadécimal | %X |
Tout sauf un chiffre hexadécimal |
%x (x non alphanumérique) |
Le caractère x littéral (échappement, ex. %. pour un point) |
Ensembles : [set] correspond à n'importe quel caractère de set ; [^set] à tout caractère
absent de set. set peut contenir des caractères littéraux, des classes (%a, %d, ...) et des
intervalles (a-z).
Quantificateurs, appliqués à l'item précédent (classe, ensemble, ou .) :
| Suffixe | Signifie |
|---|---|
* |
0 ou plus, aussi gourmand que possible |
+ |
1 ou plus, aussi gourmand que possible |
- |
0 ou plus, aussi peu que possible (paresseux) |
? |
0 ou 1 |
Ancres : ^ en tête de motif force la recherche à ne tenter qu'à la position de départ (pas de
balayage). $ en fin de motif force la fin de l'occurrence à coïncider avec la fin de s.
Captures : (...) capture la sous-chaîne correspondante — accessible en résultat de find/
match/gmatch, ou via %1-%9 dans un gabarit de gsub. () (parenthèses vides) capture la
position courante (un entier) plutôt qu'une sous-chaîne.
Constructions spéciales :
%bxy— correspond à une sous-chaîne équilibrée commençant parxet finissant pary(utile pour capturer du contenu entre parenthèses/accolades imbriquées, ex.%b()).%f[set]— « frontière » : correspond à la position de transition entre un caractère horssetet un caractère dansset, sans consommer de caractère.%1-%9dans le motif lui-même (pas dans un gabaritgsub) référencent le texte déjà capturé par la n-ième capture ouverte précédemment dans le même motif (back-reference).
for k, v in string.gmatch("a=1, b=2, c=3", "(%a+)=(%d+)") do
print(k, v)
end
print(string.match("(nested (parens) here)", "%b()"))
string.format(formatstring, ···)
Formatage façon printf en C. Chaque directive %[flags][largeur][.précision]conversion
consomme un argument (sauf %%, qui insère un % littéral). Conversions supportées :
| Conversion | Signifie |
|---|---|
d, i |
Entier signé |
u |
Entier non signé |
o |
Entier en octal |
x, X |
Entier en hexadécimal (minuscules / majuscules) |
c |
Caractère depuis son code numérique |
s |
Chaîne (tostring implicite ; .précision tronque) |
q |
Valeur formatée sous forme littérale YScript réinjectable dans du code |
f, F |
Flottant, notation décimale |
e, E |
Flottant, notation scientifique |
g, G |
Flottant, notation la plus compacte entre f/e |
a, A |
Flottant, notation hexadécimale |
Drapeaux : - (aligne à gauche), + (force le signe), (espace pour un nombre positif), 0
(remplit avec des zéros), # (forme alternative — préfixe 0x/0, point décimal forcé...).
print(string.format("%5d|%-5d|", 42, 42)) --> 42|42 |
print(string.format("%.2f", 3.14159)) --> 3.14
print(string.format("%x", 255)) --> ff
print(string.format("%q", 'he said "hi"\n')) --> "he said \"hi\"\n"
string.netformat(formatstring, ···)
Alternative à string.format utilisant la syntaxe de formatage composite .NET ("{0}",
"{1,5}", "{2:F2}", ...) plutôt que la syntaxe C-printf — pour les scripts qui veulent accéder
directement aux spécificateurs de format numériques/dates propres à .NET.
print(string.netformat("{0:F2} - {1,10}", 3.14159, "x"))
string.dump(function [, strip])
Sérialise function (qui doit être une fonction script, pas une fonction externe) en bytecode
précompilé, retourné sous forme de chaîne binaire. strip (booléen), si vrai, retire les
informations de débogage du bytecode produit. Le résultat peut être rechargé avec load.
string.pack(fmt, ···) / string.unpack(fmt, data [, pos]) / string.packsize(fmt)
Sérialisation binaire façon "struct" (compatible Lua 5.4). string.pack encode ses arguments selon
fmt en une chaîne binaire ; string.unpack fait l'inverse à partir de la position pos (défaut
1) de data, en retournant les valeurs décodées suivies de la position juste après les données
lues ; string.packsize calcule la taille en octets qu'occuperait string.pack(fmt, ···), sans
options de taille variable (s, z).
Options de fmt (peuvent être précédées de modificateurs d'ordre des octets/alignement, voir plus
bas) :
| Option | Signifie |
|---|---|
b / B |
byte signé / non signé (1 octet) |
h / H |
short signé / non signé (2 octets) |
iN / IN |
Entier signé / non signé de N octets (défaut 4, max 16) |
l / L |
Entier long signé / non signé (8 octets) |
j / J |
lua_Integer signé / non signé (8 octets) |
T |
size_t (8 octets) |
f |
Flottant simple précision (4 octets) |
d / n |
Flottant double précision (8 octets) |
sN |
Chaîne précédée de sa longueur sur N octets (défaut 8) |
z |
Chaîne terminée par un octet nul |
cN |
Chaîne de taille fixe N octets (taille obligatoire) |
x |
Un octet de remplissage (padding) |
Xop |
Aligne selon la taille de l'option op sans rien écrire |
< / > / = |
Octets faibles/forts en tête / boutisme natif |
!N |
Alignement maximal à N octets |
| espace | Ignoré (séparateur visuel) |
local packed = string.pack("<i4i4", 10, 20)
print(#packed) --> 8
local a, b, pos = string.unpack("<i4i4", packed)
print(a, b, pos) --> 10 20 9