Trabajando con cadenas

Nette\Utils\Strings es una clase estática con funciones útiles para trabajar con cadenas, principalmente en codificación UTF-8.

Instalación:

composer require nette/utils

Todos los ejemplos asumen que se ha creado un alias:

use Nette\Utils\Strings;

Cambiar mayúsculas y minúsculas

Estas funciones requieren la extensión PHP mbstring.

lower (string $s): string

Convierte una cadena UTF-8 a minúsculas.

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

upper (string $s): string

Convierte una cadena UTF-8 a mayúsculas.

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

firstUpper (string $s): string

Convierte la primera letra de una cadena UTF-8 a mayúscula, dejando el resto sin cambios.

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

firstLower (string $s): string

Convierte la primera letra de una cadena UTF-8 a minúscula, dejando el resto sin cambios.

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

capitalize (string $s): string

Convierte la primera letra de cada palabra en una cadena UTF-8 a mayúscula y el resto a minúsculas.

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

Modificar la cadena

normalize (string $s): string

Elimina caracteres de control, normaliza los saltos de línea a \n, elimina las líneas en blanco iniciales y finales, elimina los espacios finales en las líneas y normaliza UTF-8 a la forma normal NFC.

unixNewLines (string $s): string

Convierte los saltos de línea a \n utilizados en sistemas Unix. Los saltos de línea son: \n, \r, \r\n, separador de línea U+2028, separador de párrafo U+2029.

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

platformNewLines (string $s)string

Convierte los saltos de línea a los caracteres específicos de la plataforma actual, es decir, \r\n en Windows y \n en otros sistemas. Los saltos de línea son: \n, \r, \r\n, separador de línea U+2028, separador de párrafo U+2029.

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

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

Modifica una cadena UTF-8 al formato utilizado en las URL, es decir, elimina los diacríticos y reemplaza todos los caracteres, excepto las letras del alfabeto inglés y los números, por guiones.

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

Si se deben conservar otros caracteres, se pueden especificar en el segundo parámetro.

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

El tercer parámetro puede desactivar la conversión a minúsculas.

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

Requiere la extensión PHP intl.

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

Elimina espacios (u otros caracteres especificados por el segundo parámetro) del principio y final de una cadena UTF-8.

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

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

Trunca una cadena UTF-8 a la longitud máxima especificada, intentando conservar palabras completas. Si la cadena se acorta, añade puntos suspensivos al final (se puede cambiar mediante el tercer parámetro).

$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

Indenta un texto multilínea desde la izquierda. El número de indentaciones lo determina el segundo parámetro, y el carácter de indentación el tercero (el valor predeterminado es un tabulador).

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

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

Rellena una cadena UTF-8 hasta la longitud especificada repitiendo la cadena $pad por la izquierda.

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

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

Rellena una cadena UTF-8 hasta la longitud especificada repitiendo la cadena $pad por la derecha.

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

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

Devuelve una parte de la cadena UTF-8 $s especificada por la posición inicial $start y la longitud $length. Si $start es negativo, la cadena devuelta comenzará en la posición -$start` desde el final.

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

reverse (string $s): string

Invierte una cadena UTF-8.

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

length (string $s): int

Devuelve el número de caracteres (no de bytes) en una cadena UTF-8.

Este es el número de puntos de código Unicode, que puede diferir del número de grafemas.

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

startsWith (string $haystack, string $needle)bool

Comprueba si la cadena $haystack empieza por la cadena $needle.

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

Utiliza la función nativa str_starts_with().

endsWith (string $haystack, string $needle)bool

Comprueba si la cadena $haystack termina con la cadena $needle.

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

Utiliza la función nativa str_ends_with().

contains (string $haystack, string $needle)bool

Comprueba si la cadena $haystack contiene la cadena $needle.

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

Utiliza la función nativa str_contains().

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

Compara dos cadenas UTF-8 o partes de ellas sin distinguir entre mayúsculas y minúsculas. Si $length es null, se comparan las cadenas completas; si es negativo, se compara el número correspondiente de caracteres desde el final de las cadenas; en caso contrario, se compara el número correspondiente de caracteres desde el principio.

Strings::compare('Nette', 'nette');     // true
Strings::compare('Nette', 'next', 2);   // true - coincidencia de los primeros 2 caracteres
Strings::compare('Nette', 'Latte', -2); // true - coincidencia de los últimos 2 caracteres

findPrefix (…$strings): string

Encuentra el prefijo común de las cadenas. Devuelve una cadena vacía si no se encuentra un prefijo común.

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

Devuelve la parte de la cadena $haystack que precede a la n-ésima ($nth) aparición de la cadena $needle. Devuelve null si no se encuentra $needle. Si $nth es negativo, la búsqueda se realiza desde el final de la cadena.

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

Devuelve la parte de la cadena $haystack que sigue a la n-ésima ($nth) aparición de la cadena $needle. Devuelve null si no se encuentra $needle. Si $nth es negativo, la búsqueda se realiza desde el final de la cadena.

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

Devuelve la posición (en caracteres) de la n-ésima ($nth) aparición de la cadena $needle dentro de la cadena $haystack. Devuelve null si no se encuentra $needle. Si $nth es negativo, la búsqueda se realiza desde el final de la cadena.

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

Codificación

fixEncoding (string $s): string

Elimina los caracteres UTF-8 no válidos de la cadena.

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

checkEncoding (string $s)bool

Comprueba si la cadena es UTF-8 válida.

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

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

toAscii (string $s): string

Convierte una cadena UTF-8 a ASCII, es decir, elimina diacríticos, etc.

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

Requiere la extensión PHP intl.

chr (int $code): string

Devuelve un carácter específico en UTF-8 a partir de su punto de código (número en el rango 0×0000..D7FF y 0xE000..10FFFF).

Strings::chr(0xA9); // '©' en codificación UTF-8

ord (string $char): int

Devuelve el punto de código de un carácter específico en UTF-8 (número en el rango 0×0000..D7FF o 0xE000..10FFFF).

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

Expresiones regulares

La clase Strings ofrece funciones para trabajar con expresiones regulares. A diferencia de las funciones nativas de PHP, tienen una API más clara, mejor soporte para Unicode y, sobre todo, detección de errores. Cualquier error durante la compilación o el procesamiento de la expresión lanza una excepción Nette\RegexpException.

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

Divide una cadena en un array utilizando una expresión regular. Las expresiones entre paréntesis también se capturan y devuelven.

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

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

Si $skipEmpty es true, solo se devuelven los elementos no vacíos:

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

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

Si se especifica $limit, solo se devuelven subcadenas hasta ese límite, y el resto de la cadena se coloca en el último elemento. Un límite de –1 o 0 significa que no hay límite.

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

Si $utf8 es true, la evaluación cambia al modo Unicode. Similar a especificar el modificador u.

Si $captureOffset es true, para cada coincidencia encontrada, también se devolverá su posición en la cadena (en bytes; o en caracteres si se establece $utf8). Esto cambia el valor devuelto a un array donde cada elemento es un par formado por la cadena coincidente y su posición.

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

Busca en una cadena una parte que coincida con una expresión regular y devuelve un array con la expresión encontrada y sus subexpresiones individuales, o null si no hay coincidencia.

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

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

Si $unmatchedAsNull es true, las subexpresiones no capturadas se devuelven como null; de lo contrario, se devuelven como una cadena vacía o no se incluyen en el resultado:

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

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

Si $utf8 es true, la evaluación cambia al modo Unicode. Similar a especificar el modificador u:

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

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

El parámetro $offset se puede usar para especificar la posición desde la cual comenzar la búsqueda (en bytes; o en caracteres si se establece $utf8).

Si $captureOffset es true, para cada coincidencia encontrada, también se devolverá su posición en la cadena (en bytes; o en caracteres si se establece $utf8). Esto cambia el valor devuelto a un array donde cada elemento es un par formado por la cadena coincidente y su desplazamiento (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

Busca en una cadena todas las ocurrencias que coincidan con una expresión regular y devuelve un array de arrays, cada uno conteniendo la expresión encontrada y sus subexpresiones individuales.

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

Si $patternOrder es true, la estructura de los resultados cambia de modo que el primer elemento es un array de todas las coincidencias completas del patrón, el segundo es un array de las cadenas que coinciden con la primera subexpresión entre paréntesis, y así sucesivamente:

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

Si $unmatchedAsNull es true, las subexpresiones no capturadas se devuelven como null; de lo contrario, se devuelven como una cadena vacía o no se incluyen en el resultado:

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

Si $utf8 es true, la evaluación cambia al modo Unicode. Similar a especificar el modificador u:

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

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

El parámetro $offset se puede usar para especificar la posición desde la cual comenzar la búsqueda (en bytes; o en caracteres si se establece $utf8).

Si $captureOffset es true, para cada coincidencia encontrada, también se devolverá su posición en la cadena (en bytes; o en caracteres si se establece $utf8). Esto cambia el valor devuelto a un array donde cada elemento es un par formado por la cadena coincidente y su posición:

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 es true, la función devuelve un Generator en lugar de un array, lo que ofrece importantes ventajas de rendimiento al trabajar con cadenas grandes. El generador permite buscar coincidencias de forma progresiva, en lugar de procesar toda la cadena a la vez. Esto permite trabajar eficientemente incluso con textos de entrada extremadamente grandes. Además, puedes interrumpir el procesamiento en cualquier momento si encuentras la coincidencia deseada, lo que ahorra tiempo de cómputo.

$matches = Strings::matchAll($largeText, '~\w+~', lazy: true);
foreach ($matches as $match) {
    echo "Encontrado: $match[0]\n";
    // El procesamiento puede interrumpirse en cualquier momento
}

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

Reemplaza todas las ocurrencias que coinciden con una expresión regular. $replacement es una máscara para la cadena de reemplazo o una función callback.

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

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

La función también permite realizar múltiples reemplazos pasando un array en el segundo parámetro con el formato patrón => reemplazo:

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

El parámetro $limit limita el número de reemplazos realizados. Un límite de –1 significa que no hay límite.

Si $utf8 es true, la evaluación cambia al modo Unicode. Similar a especificar el modificador u.

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

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

Si $captureOffset es true, para cada coincidencia encontrada, también se pasará a la función callback su posición en la cadena (en bytes; o en caracteres si se establece $utf8). Esto cambia la forma del array pasado, donde cada elemento es un par formado por la cadena coincidente y su posición.

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

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

Si $unmatchedAsNull es true, las subexpresiones no capturadas se pasan a la función callback como null; de lo contrario, se pasan como una cadena vacía o no se incluyen:

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']
versión: 4.0