Travailler avec les chaînes de caractères

Nette\Utils\Strings est une classe statique avec des fonctions utiles pour travailler avec les chaînes de caractères, principalement en encodage UTF-8.

Installation :

composer require nette/utils

Tous les exemples supposent qu'un alias a été créé :

use Nette\Utils\Strings;

Changement de casse

Ces fonctions nécessitent l'extension PHP mbstring.

lower (string $s): string

Convertit une chaîne UTF-8 en minuscules.

Strings::lower('Dobrý den'); // 'dobrý den'

upper (string $s): string

Convertit une chaîne UTF-8 en majuscules.

Strings::upper('Dobrý den'); // 'DOBRÝ DEN'

firstUpper (string $s): string

Convertit la première lettre d'une chaîne UTF-8 en majuscule, ne change pas les autres.

Strings::firstUpper('dobrý den'); // 'Dobrý den'

firstLower (string $s): string

Convertit la première lettre d'une chaîne UTF-8 en minuscule, ne change pas les autres.

Strings::firstLower('Dobrý den'); // 'dobrý den'

capitalize (string $s): string

Convertit la première lettre de chaque mot dans une chaîne UTF-8 en majuscule, les autres en minuscules.

Strings::capitalize('Dobrý den'); // 'Dobrý Den'

Modification de chaîne

normalize (string $s): string

Supprime les caractères de contrôle, normalise les fins de ligne en \n, supprime les lignes vides de début et de fin, supprime les espaces de fin sur les lignes, normalise l'UTF-8 en forme normale NFC.

unixNewLines (string $s): string

Convertit les fins de ligne en \n utilisé dans les systèmes Unix. Les fins de ligne sont : \n, \r, \r\n, U+2028 séparateur de ligne, U+2029 séparateur de paragraphe.

$unixLikeLines = Strings::unixNewLines($string);

platformNewLines (string $s)string

Convertit les fins de ligne en caractères spécifiques à la plateforme actuelle, c'est-à-dire \r\n sous Windows et \n ailleurs. Les fins de ligne sont : \n, \r, \r\n, U+2028 séparateur de ligne, U+2029 séparateur de paragraphe.

$platformLines = Strings::platformNewLines($string);

webalize (string $s, ?string $charlist=null, bool $lower=true)string

Modifie une chaîne UTF-8 à la forme utilisée dans les URL, c'est-à-dire supprime les diacritiques et remplace tous les caractères, sauf les lettres de l'alphabet anglais et les chiffres, par un trait d'union.

Strings::webalize('náš produkt'); // 'nas-produkt'

Si d'autres caractères doivent être conservés, ils peuvent être indiqués dans le deuxième paramètre de la fonction.

Strings::webalize('10. obrázek_id', '._'); // '10.-obrazek_id'

Avec le troisième paramètre, on peut supprimer la conversion en minuscules.

Strings::webalize('Dobrý den', null, false); // 'Dobry-den'

Nécessite l'extension PHP intl.

trim (string $s, ?string $charlist=null)string

Supprime les espaces (ou autres caractères spécifiés par le deuxième paramètre) du début et de la fin d'une chaîne UTF-8.

Strings::trim('  Hello  '); // 'Hello'

truncate (string $s, int $maxLen, string $append=`'…'`)string

Tronque une chaîne UTF-8 à la longueur maximale spécifiée, en essayant de préserver les mots entiers. Si la chaîne est raccourcie, ajoute des points de suspension à la fin (peut être changé avec le troisième paramètre).

$text = 'Řekněte, jak se máte?';
Strings::truncate($text, 5);       // 'Řekn…'
Strings::truncate($text, 20);      // 'Řekněte, jak se…'
Strings::truncate($text, 30);      // 'Řekněte, jak se máte?'
Strings::truncate($text, 20, '~'); // 'Řekněte, jak se~'

indent (string $s, int $level=1, string $indentationChar=`"\t"`)string

Indente un texte multiligne depuis la gauche. Le nombre d'indentations est déterminé par le deuxième paramètre, avec quoi indenter par le troisième paramètre (la valeur par défaut est une tabulation).

Strings::indent('Nette');         // "\tNette"
Strings::indent('Nette', 2, '+'); // '++Nette'

padLeft (string $s, int $length, string $pad=`' '`)string

Remplit une chaîne UTF-8 à la longueur spécifiée en répétant la chaîne $pad depuis la gauche.

Strings::padLeft('Nette', 6);        // ' Nette'
Strings::padLeft('Nette', 8, '+*');  // '+*+Nette'

padRight (string $s, int $length, string $pad=`' '`)string

Remplit une chaîne UTF-8 à la longueur spécifiée en répétant la chaîne $pad depuis la droite.

Strings::padRight('Nette', 6);       // 'Nette '
Strings::padRight('Nette', 8, '+*'); // 'Nette+*+'

substring (string $s, int $start, ?int $length=null)string

Retourne une partie de la chaîne UTF-8 $s spécifiée par la position de départ $start et la longueur $length. Si $start est négatif, la chaîne retournée commencera par le caractère -$start depuis la fin.

Strings::substring('Nette Framework', 0, 5); // 'Nette'
Strings::substring('Nette Framework', 6);    // 'Framework'
Strings::substring('Nette Framework', -4);   // 'work'

reverse (string $s): string

Inverse une chaîne UTF-8.

Strings::reverse('Nette'); // 'etteN'

length (string $s): int

Retourne le nombre de caractères (pas d'octets) dans la chaîne UTF-8.

C'est le nombre de points de code Unicode, qui peuvent différer du nombre de graphèmes.

Strings::length('Nette');   // 5
Strings::length('červená'); // 7

startsWith (string $haystack, string $needle)bool

Détermine si la chaîne $haystack commence par la chaîne $needle.

$haystack = 'Začíná';
$needle = 'Za';
Strings::startsWith($haystack, $needle); // true

Utilisez la fonction native str_starts_with().

endsWith (string $haystack, string $needle)bool

Détermine si la chaîne $haystack se termine par la chaîne $needle.

$haystack = 'Končí';
$needle = 'čí';
Strings::endsWith($haystack, $needle); // true

Utilisez la fonction native str_ends_with().

contains (string $haystack, string $needle)bool

Détermine si la chaîne $haystack contient $needle.

$haystack = 'Posluchárna';
$needle = 'sluch';
Strings::contains($haystack, $needle); // true

Utilisez la fonction native str_contains().

compare (string $left, string $right, ?int $length=null)bool

Comparaison de deux chaînes UTF-8 ou de leurs parties sans tenir compte de la casse. Si $length contient null, les chaînes entières sont comparées, s'il est négatif, le nombre correspondant de caractères est comparé depuis la fin des chaînes, sinon le nombre correspondant de caractères est comparé depuis le début.

Strings::compare('Nette', 'nette');     // true
Strings::compare('Nette', 'next', 2);   // true - correspondance des 2 premiers caractères
Strings::compare('Nette', 'Latte', -2); // true - correspondance des 2 derniers caractères

findPrefix (…$strings): string

Trouve le début commun des chaînes. Ou retourne une chaîne vide si le préfixe commun n'a pas été trouvé.

Strings::findPrefix('prefix-a', 'prefix-bb', 'prefix-c');   // 'prefix-'
Strings::findPrefix(['prefix-a', 'prefix-bb', 'prefix-c']); // 'prefix-'
Strings::findPrefix('Nette', 'is', 'great');                // ''

before (string $haystack, string $needle, int $nth=1): ?string

Retourne la partie de la chaîne $haystack avant la n-ième occurrence $nth de la chaîne $needle. Ou null si $needle n'a pas été trouvé. Avec une valeur négative $nth, la recherche se fait depuis la fin de la chaîne.

Strings::before('Nette_is_great', '_', 1);  // 'Nette'
Strings::before('Nette_is_great', '_', -2); // 'Nette'
Strings::before('Nette_is_great', ' ');     // null
Strings::before('Nette_is_great', '_', 3);  // null

after (string $haystack, string $needle, int $nth=1): ?string

Retourne la partie de la chaîne $haystack après la n-ième occurrence $nth de la chaîne $needle. Ou null si $needle n'a pas été trouvé. Avec une valeur négative $nth, la recherche se fait depuis la fin de la chaîne.

Strings::after('Nette_is_great', '_', 2);  // 'great'
Strings::after('Nette_is_great', '_', -1); // 'great'
Strings::after('Nette_is_great', ' ');     // null
Strings::after('Nette_is_great', '_', 3);  // null

indexOf (string $haystack, string $needle, int $nth=1)?int

Retourne la position en caractères de la n-ième occurrence $nth de la chaîne $needle dans la chaîne $haystack. Ou null s'il n'a pas été trouvé $needle. Avec une valeur négative $nth, la recherche se fait depuis la fin de la chaîne.

Strings::indexOf('abc abc abc', 'abc', 2);  // 4
Strings::indexOf('abc abc abc', 'abc', -1); // 8
Strings::indexOf('abc abc abc', 'd');       // null

Encodage

fixEncoding (string $s): string

Supprime de la chaîne les caractères UTF-8 invalides.

$correctStrings = Strings::fixEncoding($string);

checkEncoding (string $s)bool

Détermine s'il s'agit d'une chaîne UTF-8 valide.

$isUtf8 = Strings::checkEncoding($string);

Utilisez Nette\Utils\Validator::isUnicode().

toAscii (string $s): string

Convertit une chaîne UTF-8 en ASCII, c'est-à-dire supprime les diacritiques, etc.

Strings::toAscii('žluťoučký kůň'); // 'zlutoucky kun'

Nécessite l'extension PHP intl.

chr (int $code): string

Retourne un caractère spécifique en UTF-8 à partir du point de code (nombre dans la plage 0×0000..D7FF et 0xE000..10FFFF).

Strings::chr(0xA9); // '©' en encodage UTF-8

ord (string $char): int

Retourne le point de code d'un caractère spécifique en UTF-8 (nombre dans la plage 0×0000..D7FF ou 0xE000..10FFFF).

Strings::ord('©'); // 0xA9

Expressions régulières

La classe Strings offre des fonctions pour travailler avec les expressions régulières. Contrairement aux fonctions natives de PHP, elles disposent d'une API plus compréhensible, d'un meilleur support Unicode et surtout d'une détection d'erreurs. Toute erreur lors de la compilation ou du traitement de l'expression lance une exception Nette\RegexpException.

split (string $subject, string $pattern, bool $captureOffset=false, bool $skipEmpty=false, int $limit=-1, bool $utf8=false)array

Divise une chaîne en tableau selon une expression régulière. Les expressions entre parenthèses seront capturées et retournées également.

Strings::split('hello, world', '~,\s*~');
// ['hello', 'world']

Strings::split('hello, world', '~(,)\s*~');
// ['hello', ',', 'world']``

Si $skipEmpty est true, seuls les éléments non vides seront retournés :

Strings::split('hello, world, ', '~,\s*~');
// ['hello', 'world', '']

Strings::split('hello, world, ', '~,\s*~', skipEmpty: true);
// ['hello', 'world']

Si $limit est spécifié, seules les sous-chaînes jusqu'à la limite seront retournées et le reste de la chaîne sera placé dans le dernier élément. Une limite de –1 ou 0 signifie aucune restriction.

Strings::split('hello, world, third', '~,\s*~', limit: 2);
// ['hello', 'world, third']

Si $utf8 est true, l'évaluation passe en mode Unicode. Similaire à quand vous spécifiez le modificateur u.

Si $captureOffset est true, pour chaque correspondance trouvée, sa position dans la chaîne sera également retournée (en octets ; si $utf8 est défini, alors en caractères). Cela change la valeur de retour en tableau, où chaque élément est une paire composée de la chaîne correspondante et de sa position.

Strings::split('žlutý, kůň', '~,\s*~', captureOffset: true);
// [['žlutý', 0], ['kůň', 9]]

Strings::split('žlutý, kůň', '~,\s*~', captureOffset: true, utf8: true);
// [['žlutý', 0], ['kůň', 7]]

match (string $subject, string $pattern, bool $captureOffset=false, int $offset=0, bool $unmatchedAsNull=false, bool $utf8=false)?array

Recherche dans la chaîne une partie correspondant à l'expression régulière et retourne un tableau avec l'expression trouvée et les sous-expressions individuelles, ou null.

Strings::match('hello!', '~\w+(!+)~');
// ['hello!', '!']

Strings::match('hello!', '~X~');
// null

Si $unmatchedAsNull est true, les sous-modèles non capturés sont retournés comme null ; sinon, ils sont retournés comme une chaîne vide ou non retournés :

Strings::match('hello', '~\w+(!+)?~');
// ['hello']

Strings::match('hello', '~\w+(!+)?~', unmatchedAsNull: true);
// ['hello', null]

Si $utf8 est true, l'évaluation passe en mode Unicode. Similaire à quand vous spécifiez le modificateur u :

Strings::match('žlutý kůň', '~\w+~');
// ['lut']

Strings::match('žlutý kůň', '~\w+~', utf8: true);
// ['žlutý']

Le paramètre $offset peut être utilisé pour spécifier la position à partir de laquelle commencer la recherche (en octets ; si $utf8 est défini, alors en caractères).

Si $captureOffset est true, pour chaque correspondance trouvée, sa position dans la chaîne sera également retournée (en octets ; si $utf8 est défini, alors en caractères). Cela change la valeur de retour en tableau, où chaque élément est une paire composée de la chaîne correspondante et de son offset :

Strings::match('žlutý!', '~\w+(!+)?~', captureOffset: true);
// [['lut', 2]]

Strings::match('žlutý!', '~\w+(!+)?~', captureOffset: true, utf8: true);
// [['žlutý!', 0], ['!', 5]]

matchAll (string $subject, string $pattern, bool $captureOffset=false, int $offset=0, bool $unmatchedAsNull=false, bool $patternOrder=false, bool $utf8=false, bool $lazy=false): array|Generator

Recherche dans la chaîne toutes les occurrences correspondant à l'expression régulière et retourne un tableau de tableaux avec l'expression trouvée et les sous-expressions individuelles.

Strings::matchAll('hello, world!!', '~\w+(!+)?~');
/* [
	0 => ['hello'],
	1 => ['world!!', '!!'],
] */

Si $patternOrder est true, la structure des résultats change de sorte que dans le premier élément se trouve un tableau des correspondances complètes du modèle, dans le deuxième se trouve un tableau des chaînes auxquelles correspond le premier sous-modèle entre parenthèses, et ainsi de suite :

Strings::matchAll('hello, world!!', '~\w+(!+)?~', patternOrder: true);
/* [
	0 => ['hello', 'world!!'],
	1 => ['', '!!'],
] */

Si $unmatchedAsNull est true, les sous-modèles non capturés sont retournés comme null ; sinon, ils sont retournés comme une chaîne vide ou non retournés :

Strings::matchAll('hello, world!!', '~\w+(!+)?~', unmatchedAsNull: true);
/* [
	0 => ['hello', null],
	1 => ['world!!', '!!'],
] */

Si $utf8 est true, l'évaluation passe en mode Unicode. Similaire à quand vous spécifiez le modificateur u :

Strings::matchAll('žlutý kůň', '~\w+~');
/* [
	0 => ['lut'],
	1 => ['k'],
] */

Strings::matchAll('žlutý kůň', '~\w+~', utf8: true);
/* [
	0 => ['žlutý'],
	1 => ['kůň'],
] */

Le paramètre $offset peut être utilisé pour spécifier la position à partir de laquelle commencer la recherche (en octets ; si $utf8 est défini, alors en caractères).

Si $captureOffset est true, pour chaque correspondance trouvée, sa position dans la chaîne sera également retournée (en octets ; si $utf8 est défini, alors en caractères). Cela change la valeur de retour en tableau, où chaque élément est une paire composée de la chaîne correspondante et de sa position :

Strings::matchAll('žlutý kůň', '~\w+~', captureOffset: true);
/* [
	0 => [['lut', 2]],
	1 => [['k', 8]],
] */

Strings::matchAll('žlutý kůň', '~\w+~', captureOffset: true, utf8: true);
/* [
	0 => [['žlutý', 0]],
	1 => [['kůň', 6]],
] */

Si $lazy est true, la fonction retourne un Generator au lieu d'un tableau, ce qui apporte des avantages significatifs en termes de performance lors du travail avec de grandes chaînes. Le générateur permet de rechercher les correspondances progressivement, au lieu de toute la chaîne en une fois. Cela permet de travailler efficacement même avec des textes d'entrée extrêmement grands. De plus, vous pouvez interrompre le traitement à tout moment si vous trouvez la correspondance recherchée, ce qui économise du temps de calcul.

$matches = Strings::matchAll($largeText, '~\w+~', lazy: true);
foreach ($matches as $match) {
    echo "Trouvé: $match[0]\n";
    // Le traitement peut être interrompu à tout moment
}

replace (string $subject, string|array $pattern, string|callable $replacement='', int $limit=-1, bool $captureOffset=false, bool $unmatchedAsNull=false, bool $utf8=false)string

Remplace toutes les occurrences correspondant à l'expression régulière. $replacement est soit un masque de chaîne de remplacement, soit un callback.

Strings::replace('hello, world!', '~\w+~', '--');
// '--, --!'

Strings::replace('hello, world!', '~\w+~', fn($m) => strrev($m[0]));
// 'olleh, dlrow!'

La fonction permet également d'effectuer plusieurs remplacements en passant dans le deuxième paramètre un tableau sous la forme pattern => replacement :

Strings::replace('hello, world!', [
	'~\w+~' => '--',
	'~,\s+~' => ' ',
]);
// '-- --!'

Le paramètre $limit limite le nombre de remplacements effectués. Une limite de –1 signifie aucune restriction.

Si $utf8 est true, l'évaluation passe en mode Unicode. Similaire à quand vous spécifiez le modificateur u.

Strings::replace('žlutý kůň', '~\w+~', '--');
// 'ž--ý --ůň'

Strings::replace('žlutý kůň', '~\w+~', '--', utf8: true);
// '-- --'

Si $captureOffset est true, pour chaque correspondance trouvée, sa position dans la chaîne sera également passée au callback (en octets ; si $utf8 est défini, alors en caractères). Cela change la forme du tableau passé, où chaque élément est une paire composée de la chaîne correspondante et de sa position.

Strings::replace(
	'žlutý kůň',
	'~\w+~',
	function (array $m) { dump($m); return ''; },
	captureOffset: true,
);
// dumps [['lut', 2]] et [['k', 8]]

Strings::replace(
	'žlutý kůň',
	'~\w+~',
	function (array $m) { dump($m); return ''; },
	captureOffset: true,
	utf8: true,
);
// dumps [['žlutý', 0]] et [['kůň', 6]]

Si $unmatchedAsNull est true, les sous-modèles non capturés sont passés au callback comme null ; sinon, ils sont passés comme une chaîne vide ou non passés :

Strings::replace(
	'ac',
	'~(a)(b)*(c)~',
	function (array $m) { dump($m); return ''; },
);
// dumps ['ac', 'a', '', 'c']

Strings::replace(
	'ac',
	'~(a)(b)*(c)~',
	function (array $m) { dump($m); return ''; },
	unmatchedAsNull: true,
);
// dumps ['ac', 'a', null, 'c']
version: 4.0