Funciones para cadenas

Nette\Utils\Strings es una clase estática con funciones útiles para trabajar con cadenas codificadas en UTF-8.

Instalación:

composer require nette/utils

Todos los ejemplos suponen que está definido el siguiente alias de clase:

use Nette\Utils\Strings;

Mayúsculas y minúsculas

Estas funciones requieren la extensión mbstring de PHP.

lower (string $s): string

Convierte una cadena UTF-8 a minúsculas.

Strings::lower('Hello World'); // 'hello world'

upper (string $s): string

Convierte una cadena UTF-8 a mayúsculas.

Strings::upper('Hello World'); // 'HELLO WORLD'

firstUpper (string $s): string

Convierte el primer carácter de una cadena UTF-8 a mayúscula y deja los demás sin cambios.

Strings::firstUpper('hello world'); // 'Hello world'

firstLower (string $s): string

Convierte el primer carácter de una cadena UTF-8 a minúscula y deja los demás sin cambios.

Strings::firstLower('Hello world'); // 'hello world'

capitalize (string $s): string

Convierte a mayúscula el primer carácter de cada palabra de una cadena UTF-8 y el resto a minúsculas.

Strings::capitalize('hello world'); // 'Hello World'

Modificar una cadena

normalize (string $s): string

Elimina los caracteres de control, normaliza los finales de línea a \n, recorta las líneas vacías del principio y del final, elimina los espacios finales de las líneas y normaliza el UTF-8 a la forma normal NFC.

unixNewLines (string $s): string

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

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

platformNewLines (string $s)string

Convierte los finales de línea a los caracteres propios de la plataforma actual, es decir, \r\n en Windows y \n en el resto. Los finales de línea son: \n, \r, \r\n, el separador de línea U+2028 y el separador de párrafo U+2029.

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

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

Adapta una cadena UTF-8 a la forma usada en las URL, es decir, elimina los diacríticos y sustituye por guiones todos los caracteres que no sean letras del alfabeto inglés o números.

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

Si deben conservarse otros caracteres, se pueden indicar en el segundo parámetro.

Strings::webalize('10. image_id', '._'); // '10.-image_id'

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

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

Requiere la extensión intl de PHP.

trim (string $s, string $charlist=self::TrimCharacters)string

Elimina los espacios en blanco (u otros caracteres indicados en el segundo parámetro) del principio y del final de una cadena UTF-8.

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

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

Acorta una cadena UTF-8 hasta la longitud máxima indicada, procurando conservar palabras enteras. Si la cadena se acorta, se añaden al final unos puntos suspensivos (modificables con el tercer parámetro).

$text = 'Hello, how are you today?';
Strings::truncate($text, 5);       // 'Hell…'
Strings::truncate($text, 20);      // 'Hello, how are you…'
Strings::truncate($text, 30);      // 'Hello, how are you today?'
Strings::truncate($text, 20, '~'); // 'Hello, how are you~'

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

Sangra por la izquierda un texto de varias líneas. El segundo parámetro indica el número de caracteres de sangría y el tercero, el carácter o los caracteres que se usan para sangrar (de forma predeterminada, el 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 indicada anteponiendo por la izquierda la cadena $pad.

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 indicada añadiendo por la derecha la cadena $pad.

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

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

Devuelve la parte de la cadena UTF-8 $s indicada por la posición inicial $start y la longitud $length. Si $start es negativo, la cadena devuelta empezará en el carácter $start contado 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) de una cadena UTF-8.

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 = 'Starts';
$needle = 'St';
Strings::startsWith($haystack, $needle); // true

Use la función nativa str_starts_with().

endsWith (string $haystack, string $needle)bool

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

$haystack = 'Ends';
$needle = 'ds';
Strings::endsWith($haystack, $needle); // true

Use la función nativa str_ends_with().

contains (string $haystack, string $needle)bool

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

$haystack = 'Auditorium';
$needle = 'dit';
Strings::contains($haystack, $needle); // true

Use 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 mayúsculas. Si $length es null, compara las cadenas enteras. Si es negativo, compara ese número de caracteres desde el final de las cadenas. En los demás casos, compara ese número de caracteres desde el principio.

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

findPrefix (array $strings)string

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

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 anterior a la aparición número $nth de la cadena $needle. Devuelve null si no se encuentra $needle. Si $nth es negativo, busca 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 posterior a la aparición número $nth de la cadena $needle. Devuelve null si no se encuentra $needle. Si $nth es negativo, busca 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 aparición número $nth de la cadena $needle dentro de la cadena $haystack. Devuelve null si no se encuentra $needle. Si $nth es negativo, busca 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 de una cadena los caracteres UTF-8 no válidos.

$correctString = Strings::fixEncoding($invalidString);

checkEncoding (string $s)bool

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

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

Use Nette\Utils\Validators::isUnicode().

toAscii (string $s): string

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

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

Requiere la extensión intl de PHP.

chr (int $code): string

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

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

ord (string $c): int

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

Strings::ord('©'); // 169 (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 comprensible, mejor soporte de Unicode y, sobre todo, detección de errores. Cualquier error durante la compilación o el procesamiento de la expresión lanza 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 mediante una expresión regular. Las expresiones entre paréntesis también se capturan y se 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 indica $limit, solo se devuelven las 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 sin límite.

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

Si $utf8 es true, la evaluación pasa al modo Unicode, como al usar el modificador u.

Si $captureOffset es true, se devuelve también la posición de cada coincidencia en la cadena (en bytes; en caracteres si $utf8 está activo). Esto cambia el valor de retorno a un array donde cada elemento es una pareja formada 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]] // las posiciones son en caracteres

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 encaje con una expresión regular y devuelve un array con la expresión encontrada y las distintas subexpresiones, o null si no encuentra ninguna coincidencia.

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

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

Si $unmatchedAsNull es true, los subpatrones no capturados se devuelven como null; en caso contrario, se devuelven como cadena vacía o se omiten por completo:

Strings::match('hello', '~\w+(!+)?~');
// ['hello'] (el grupo opcional !+ no coincidió)

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

Si $utf8 es true, la evaluación pasa al modo Unicode, como al usar el modificador u:

Strings::match('žlutý kůň', '~\w+~'); // Sin UTF-8
// ['lut'] (solo coincide con caracteres de palabra ASCII)

Strings::match('žlutý kůň', '~\w+~', utf8: true); // Con UTF-8
// ['žlutý'] (coincide con caracteres de palabra Unicode)

El parámetro $offset puede indicar la posición inicial de la búsqueda (en bytes; en caracteres si $utf8 está activo).

Si $captureOffset es true, se devuelve también la posición de cada coincidencia en la cadena (en bytes; en caracteres si $utf8 está activo). Esto cambia el valor de retorno a un array donde cada elemento es una pareja formada por la cadena coincidente y su desplazamiento:

Strings::match('žlutý!', '~\w+(!+)?~', captureOffset: true); // Sin UTF-8
// [['lut', 2]] (solo coincidencia ASCII, desplazamiento en bytes)

Strings::match('žlutý!', '~\w+(!+)?~', captureOffset: true, utf8: true); // Con UTF-8
// [['žlutý!', 0], ['!', 5]] (coincidencia Unicode, desplazamientos en caracteres)

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 apariciones que encajen con una expresión regular y devuelve un array de arrays con la expresión encontrada y las distintas subexpresiones.

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

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

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

Si $unmatchedAsNull es true, los subpatrones no capturados se devuelven como null; en caso contrario, se devuelven como cadena vacía o se omiten:

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

Si $utf8 es true, la evaluación pasa al modo Unicode, como al usar 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 puede indicar la posición inicial de la búsqueda (en bytes; en caracteres si $utf8 está activo).

Si $captureOffset es true, se devuelve también la posición de cada coincidencia en la cadena (en bytes; en caracteres si $utf8 está activo). Esto cambia la estructura del valor de retorno: cada elemento de coincidencia es una pareja [cadena_coincidente, 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. Esto aporta ventajas notables de rendimiento al trabajar con cadenas grandes, ya que las coincidencias se encuentran de forma incremental en vez de procesar toda la cadena de una vez. Así se pueden manejar con eficacia entradas enormes. Además, puede interrumpir el procesamiento en cualquier momento si encuentra la coincidencia buscada, con el consiguiente ahorro de tiempo de cálculo.

$matches = Strings::matchAll($largeText, '~\w+~', lazy: true);
foreach ($matches as $match) {
    echo "Found: $match[0]\n";
    // El procesamiento se puede interrumpir en cualquier momento, p. ej. con break;
}

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

Sustituye todas las apariciones que encajen con una expresión regular. $replacement es una máscara de cadena de sustitución 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 permite además varias sustituciones a la vez pasando como segundo parámetro un array con el formato patrón => sustitución:

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

El parámetro $limit restringe el número de sustituciones realizadas. Un límite de –1 significa sin límite.

Si $utf8 es true, la evaluación pasa al modo Unicode, como al usar el modificador u.

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

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

Si $captureOffset es true, al callback se le pasa también la posición de cada coincidencia en la cadena (en bytes; en caracteres si $utf8 está activo). Esto cambia la estructura del array pasado: cada elemento es una pareja [cadena_coincidente, posición].

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

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

Si $unmatchedAsNull es true, los subpatrones no capturados se pasan al callback como null; en caso contrario, se pasan como cadena vacía o se omiten:

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

Strings::replace(
	'ac',
	'~(a)(b)*(c)~',
	function (array $m) { dump($m); return ''; },
	unmatchedAsNull: true,
);
// vuelca ['ac', 'a', null, 'c']
versión: 4.x