php - stript - Compruebe una cadena para caracteres ordenados alfabéticamente
quitar tags php (13)
¡Menos bucle y si condición!
function alphacheck($str, $i=4)
{
$alpha = ''abcdefghijklmnopqrstuvwxyz'';
$len = strlen($str);
for($j=0; $j <= $len - $i; $j++){
if(strrpos($alpha, substr($str, $j, $i)) !== false){
return true;
}
}
return false;
}
Esto parece tan obvio, pero no puedo encontrar una manera de hacer esto.
Creo que incluso hay una función regular de PHP para hacer esto, pero incluso esa permanece bien oculta después de 1,5 horas de búsquedas intensivas en Google.
Lo que quiero
- Una función que toma una cadena como entrada.
- Verifica esa cadena el número de veces que tiene secuencias ordenadas alfabéticamente de más de 3 caracteres:
- devuelve true si se ha encontrado una secuencia de más de 3.
Ejemplo
"youlookgreatbcdetoday" => tiene "bcde" en él ... así que tiene que devolver verdadero
"youlookgreatklmtoday" => solo tiene "klm" en él ... así que tiene que devolver falso
"youlookgreattoday" => no tiene secuencias ordenadas alfabéticamente, así que devuelve falso
Posible caso de uso
- Comprobador de fuerza de contraseña
- juego de palabras
- ...
descargo de responsabilidad: me gustaría tener ya algún código para mostrarles, pero literalmente todavía no tengo nada.
Lo único que se me ocurrió fue dividir la cuerda en una matriz y hacer algo de magia en la matriz ... pero incluso entonces me quedé atascado.
Espero que alguno de ustedes me salve :)
Aquí hay una solución simple que se me ocurrió:
function alphaCheck($str){
$array=str_split(strtolower($str));
$minMatchLength=3;
$check=array(ord($array[0]));
foreach($array as $letter){
$ascii=ord($letter);
if($ascii==end($check)+1){
$check[]=$ascii;
if(count($check)==$minMatchLength)
return true;
}else{
unset($check);
$check=array($ascii);
}
}
return false;
}
$str="abcdhello";
$str2="testing";
$str3="abdcefghi";
if(alphaCheck($str))
echo"STR GOOD";
if(alphaCheck($str2))
echo "STR2 GOOD";
if(alphaCheck($str3))
echo "STR3 GOOD";
La salida es STR BUENO y STR3 BUENO. $minMatchLength
es el número de caracteres en una fila que deben estar para que la función devuelva verdadero. ("testing" tiene "st", pero la longitud es 3, por lo que devuelve false.
EDITAR Lo actualicé para verificar también "AbCdE" ya que solo ord
solo no funcionará para esto.
Entonces, comencemos con una implementación trivial usando un bucle y un contador (solo para aumentar):
function hasOrderedCharactersForward($string, $num = 4) {
$len = strlen($string);
$count = 0;
$last = 0;
for ($i = 0; $i < $len; $i++) {
$current = ord($string[$i]);
if ($current == $last + 1) {
$count++;
if ($count >= $num) {
return true;
}
} else {
$count = 1;
}
$last = $current;
}
return false;
}
¿Entonces, cómo funciona? Básicamente, recorre y comprueba si el orden (número ASCII) del personaje es uno más que el anterior. Si es así, aumenta el parámetro de conteo. De lo contrario, lo establece en 1 (ya que ya procesamos ese carácter). Luego, si $count
es cada vez más o igual al número solicitado, sabemos que encontramos una secuencia y podemos devolver ...
Entonces, ahora vamos a ver en ambas direcciones:
function hasOrderedCharacters($string, $num = 4) {
$len = strlen($string);
$count = 0;
$dir = 1;
$last = 0;
for ($i = 0; $i < $len; $i++) {
$current = ord($string[$i]);
if ($count == 1 && $current == $last - 1) {
$count++;
$dir = -1;
if ($count >= $num) {
return true;
}
} elseif ($current == $last + $dir) {
$count++;
if ($count >= $num) {
return true;
}
} else {
$count = 1;
$dir = 1;
}
$last = $current;
}
return false;
}
Ahora, volverá true para abcd
y dcba
...
Ahora, aquí hay una solución mucho más simple:
function hasOrderedCharactersForward($string, $num = 4) {
$len = strlen($string) + 1;
$array = array_map(
function($m) use (&$len) {
return ord($m[0]) + $len--;
},
str_split($string, 1)
);
$str = implode(''_'', $array);
$regex = ''#(^|_)(/d+)'' . str_repeat(''_/2'', $num - 1) . ''(_|$)#'';
return (bool) preg_match($regex, $str);
}
Y ahí tienes. Usamos la propiedad de que si agregamos un número decreciente a cada posición, las secuencias consecutivas aparecerán como el mismo número. Y así es exactamente cómo funciona esto.
Y aquí está la misma teoría aplicada a ambas direcciones:
function hasOrderedCharacters($string, $num = 4) {
$i = 0;
$j = strlen($string);
$str = implode('''', array_map(function($m) use (&$i, &$j) {
return chr((ord($m[0]) + $j--) % 256) . chr((ord($m[0]) + $i++) % 256);
}, str_split($string, 1)));
return preg_match(''#(.)(./1){'' . ($num - 1) . ''}#'', $str);
}
Esta es mi opinión:
function checkConsecutiveness($string, $length = 3)
{
$tempCount = 1;
for($i = 0; $i < count($tokens = str_split(strtolower($string)) ); $i++)
{
// if current char is not alphabetic or different from the next one, reset counter
if(
ord($tokens[$i]) < 97 ||
ord($tokens[$i]) > 122 ||
ord($tokens[$i]) != (ord( $tokens[$i+1]) -1)
){
$tempCount = 1;
}
// else if we met given length, return true
else if(++$tempCount >= $length)
return true;
}
// no condition met by default
return false;
}
Comprueba $string
contra cualquier secuencia de letras de $length
consecutiva.
checkConsecutiveness(''1@abcde1'', 5) // returns true;
checkConsecutiveness(''1@abcd1'', 5) // returns false;
Tenga en cuenta que el carácter actual está en el rango de 97-122, ya que la marca `[ ASCII # 96] y la llave abierta {[ASCII # 123] podrían llevar a un falso positivo.
Esto es lo que se me ocurrió:
/**
* @param string $input Input string
* @param int $length Length of required sequence
*
* @return bool
*/
function look_for_sequence($input, $length) {
//If length of sequence is larger than input string, no sequence is possible.
if ($length > strlen($input)) {
return false;
}
//Normalize string, only lowercase
//(That''s because character codes for lowercase and uppercase are different).
$input = strtolower($input);
//We loop until $length characters before the end of the string, because after that,
//No match can be found.
for ($i = 0; $i < strlen($input) - $length; $i++) {
//Reset sequence counter
$sequence = 1;
//Character under inspection.
$current_character = ord($input[$i]);
//Let''s look forward, $length characters forward:
for ($j = $i + 1; $j <= $i + $length; $j++) {
$next_character = ord($input[$j]);
//If this next character is actually the sequencing character after the current
if ($next_character == $current_character+1) {
//Increase sequence counter
$sequence++;
//Reset the current character, and move to the next
$current_character = $next_character;
//If $length characters of sequence is found, return true.
if ($sequence >= $length) {
return true;
}
}
//If the next character is no sequencing,
//break this inner loop and continue to the next character.
else {
break;
}
}
}
return false;
}
var_dump(look_for_sequence("youlookgreatbcdetoday", 4));
Trabajé en cualquier cuerda que le lancé, ¡y también puedes elegir cuántos personajes quieres contar! Yey
Mis dos centavos:
function countOrderedCharacters($str, $count){
$matches = array();
preg_replace_callback(''/(?=(/w{''.$count.''}))/'',function($x) use(&$matches,$count) {
$seq = $x[1];
if($count === 1){
$matches[] = $seq;
return;
}
$dif = ord($seq[1]) - ord($seq[0]);
if (abs($dif)!=1) return;
for($i = 0 ; $i < strlen($seq)-1 ; $i++){
if(ord($seq[$i+1]) - ord($seq[$i]) != $dif) return;
}
$matches[] = $seq;
}, $str);
return $matches;
}
Prueba esta función:
function checkForString($string,$l=4){
$length = strlen($string);
$result = 0;
for($i=0;$i<$length-1 && $result<4;$i++){
if($string[$i+1] == $string[$i]++) $result++;
}
if($result>=4) return true;
else return false;
}
Puede hacerlo así (los códigos ASCII están en orden con el alfabeto):
function check_str_for_sequences($str, $min = 3) {
$last_char_code = -1;
$total_correct = 0;
$str = strtolower($str);
for($i = 0; $i < strlen($str); $i++) {
//next letter in the alphabet from last char?
if(ord($str[$i]) == ($last_char_code + 1)) {
$total_correct++;
//min sequence reached?
if($total_correct >= ($min - 1)) {
return TRUE;
}
} else {
$total_correct = 0;
}
$last_char_code = ord($str[$i]);
}
return FALSE;
}
Uso:
$test = ''Lorem ipsum dolor abcsit amet'';
echo ''----->'' . check_str_for_alpha($test); // ----->1
Puede intentar usar el ord()
PHP para obtener el valor ASCII de cada carácter e iterar a través de su cadena carácter por carácter comparando cada valor para encontrar las secuencias.
Esto puede ayudar:
function checkForSequences($str, $minSequenceLength = 4) {
$length = strlen($str);
$sequenceLength = 1;
$reverseSequenceLength = 1;
for ($i = 1; $i < $length; $i++) {
$currChar = ord(strtolower($str[$i]));
$prevChar = ord(strtolower($str[$i - 1])) + 1;
if ($currChar == $prevChar) {
// we have two-letters back to back; increment the counter!
$sequenceLength++;
if ($sequenceLength == $minSequenceLength) {
// we''ve reached our threshold!
return true;
}
// reset the reverse-counter
$reverseSequenceLength = 1;
} else if ($currChar == ($prevChar - 2)) {
// we have two-letters back to back, in reverse order; increment the counter!
$reverseSequenceLength++;
if ($reverseSequenceLength == $minSequenceLength) {
// we''ve reached our threshold!
return true;
}
// reset the forward-counter
$sequenceLength = 1;
} else {
// no sequence; reset counter
$sequenceLength = 1;
$reverseSequenceLength = 1;
}
}
return false;
}
Lo que esta función hará es iterar a través de la cadena de caracteres por carácter. Utilizará ord()
para obtener el valor ASCII del carácter actual y compararlo con el valor ASCII del carácter anterior . Si están en secuencia, ya sea hacia adelante o hacia atrás, se incrementa un contador. Cuando el contador golpea 4
, devuelve true
!
Esto coincidirá con la secuencia directa e inversa, así como con el caso de ignorar. Entonces, abcd
coincidirá, aBcD
, y también DcBa
, ¡entre otros!
Tal vez simplista? Si desea distinguir entre mayúsculas y minúsculas, podría usar stripos()
lugar.
function abc($test, $depth) {
$alpha = ''abcdefghijklmnopqrstuvwxyz'';
$matches = 0;
$length = strlen($test);
while ($length--) {
$char = substr($test, $length, $depth);
if (strlen($char) == $depth && strpos($alpha, $char) !== false) {
$matches++;
}
if ($matches == $depth) return true;
}
return false;
}
Y (robando la observación de IRCMaxwell) con strrev()
:
function abc($test, $depth) {
$alpha = ''abcdefghijklmnopqrstuvwxyz'';
$matches = 0;
$length = strlen($test);
while ($length--) {
$char = substr($test, $length, $depth);
if (strlen($char) == $depth &&
(strpos($alpha, $char) !== false ||
strpos(strrev($alpha), $char) !== false)) {
$matches++;
}
if ($matches == $depth) return true;
}
return false;
}
También es trivial hacer con una expresión regular :
preg_match(''/ ((?=ab|bc|cd|de|ef|fg|gh).) {2,} /smix'', "testabc")
Obviamente necesitas completar la lista de cartas sucesivas. Y {2,}
simplemente busca un mínimo de tres letras en un rango.
la comparación de la desigualdad de los caracteres utiliza implícitamente el valor ord (). Aquí hay un script simple, que puede ser ajustado (particularmente para la insensibilidad a los casos):
<?php
$string = "thisabcdef";
function hasSequence($string, $sequence_length = 3) {
$num_in_order = 0;
for($i = 1; $i < strlen($string); $i++) {
if($string[$i] > $string[$i-1]) {
$num_in_order++;
} else {
$num_in_order = 0;
}
if($num_in_order >= $sequence_length) {
return TRUE;
}
}
return FALSE;
}
if(hasSequence("testabcd")) {
echo "YUP";
} else {
echo "NOPE";
}
echo "/n";
<?php
function check($input, $length = 4)
{
$sequence = "abcdefghijklmnopqrstuvwxyz";
$sequence .= substr($sequence, 0, $length - 1);
// abcdefghijklmnopqrstuvwxyz is converted to abcdefghijklmnopqrstuvwxyzabc
for ($i = 0; $i < strlen($sequence) - $length; $i++) {
// loop runs for $i = 0...25
if (strpos($input, substr($sequence, $i, $length)) !== false) {
echo sprintf(''"%s" contains "%s"'' . PHP_EOL, $input, substr($sequence, $i, $length));
return true;
}
}
echo sprintf(''"%s" is OK'' . PHP_EOL, $input);
return false;
}
check("youlookgreatbcdetoday"); // "youlookgreatbcdetoday" contains "bcde"
check("youlookgreatklmtoday"); // "youlookgreatklmtoday" is OK
check("youlookgreattoday"); // "youlookgreattoday" is OK
check("youlookgreattodayza"); // "youlookgreattodayza" is OK
check("youlookgreattodayzab"); // "youlookgreattodayzab" contains "yzab"