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']