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