La manera más rápida es con una máscara de bits. No hay funciones de cadenas torpes ni expresiones regulares. PHP es un contenedor de C, por lo que puede manipular los bits con bastante facilidad si sabe que su función lógica como OR, NOT, AND, XOR, NAND, etc ..:
function swapCase($string) {
for ($i = 0; $i < strlen($string); $i++) {
$char = ord($string{$i});
if (($char > 64 && $char < 91) || ($char > 96 && $char < 123)) {
$string{$i} = chr($char^32);
}
}
return $string;
}
Esto es lo que cambia:
$string{$i} = chr($char^32);
tomamos el carácter número N en $string
y realizar un XOR (^) dice al intérprete que tomar el valor entero de $char
e intercambiando el sexto bit (32) de un 1 a 0 o de 0 a 1.
Todos los caracteres ASCII están a 32 de distancia de sus contrapartes (ASCII era un ingenioso diseño debido a esto. Como 32 tiene una potencia de 2 (2^5), es fácil desplazar bits. Para obtener el valor ASCII de una carta, utilizar el construido en función de PHP ord()
:
ord('a') // 65
ord('A') // 97
// 97 - 65 = 32
Así se recorre a través de la cadena mediante strlen()
como la parte media del bucle for
, y se repetirá exactamente el número de veces como su cadena tiene letras. Si el carácter en la posición $i
es una letra (a-z (65-90) o A-Z (97-122)), intercambiará ese carácter para la contraparte mayúscula o minúscula utilizando una máscara de bits.
Así es como funciona la máscara de bits:
0100 0001 // 65 (lowercase a)
0010 0000 // 32 (bitmask of 32)
--------- // XOR means: we put a 1 if the bits are different, a 0 if they are same.
0110 0001 // 97 (uppercase A)
Podemos revertirla:
0110 0001 // 97 (A)
0010 0000 // Bitmask of 32
---------
0100 0001 // 65 (a)
No hay necesidad de str_replace
o preg_replace
, que sólo cambio bits para sumar o restar 32 desde el valor ASCII de el personaje y nosotros intercambiamos casos. El 6º bit (6º desde la derecha) determina si el carácter está en mayúscula o minúscula. Si es un 0, es minúscula y 1 si es mayúscula. Cambiar el bit de un 0 a un anuncio 32, obteniendo el valor en mayúscula chr()
, y cambiar de un 1 a un 0 resta 32, convirtiendo una letra mayúscula en minúscula.
swapCase('userId'); // USERiD
swapCase('USERiD'); // userId
swapCase('rot13'); // ROT13
También podemos tener una función que intercambie el caso de un personaje en particular:
// $i = position in string
function swapCaseAtChar($string, $i) {
$char = ord($string{$i});
if (($char > 64 && $char < 91) || ($char > 96 && $char < 123)) {
$string{$i} = chr($char^32);
return $string;
} else {
return $string;
}
}
echo swapCaseAtChar('iiiiiiii', 0); // Iiiiiiii
echo swapCaseAtChar('userid', 4); // userId
// Numbers are no issue
echo swapCaseAtChar('12345qqq', 7); // 12345qqQ
¿Alguna idea de cómo comprobar el caso de una cadena? – tarnfeld
Esto probablemente solo funcionará para caracteres ASCII. La alternativa a 'strotolower()' podría ser 'mb_strtolower()'. – Messa
'ctype_lower()' http://php.net/manual/en/function.ctype-lower.php –