20 votos

Comprobar una cadena por orden alfabético de personajes

Esto parece tan evidente , pero no puedo encontrar una manera de hacer esto.
Creo que hay incluso un regular de la función de PHP para hacer esto, pero hasta que uno se queda oculto tras 1,5 horas de intensas búsquedas de Google.

Lo que quiero

  • Una función que toma una cadena como entrada.
  • Comprueba que la cadena para el número de veces que se ha alfabético orderded secuencias de más de 3 caracteres:
  • devuelve true si una secuencia de más de 3 ha sido encontrado.

Ejemplo

"youlookgreatbcdetoday" = > "bcde" en ella ... así que tiene que devolver true
"youlookgreatklmtoday" => sólo tiene que "klm" en él ... así que tiene que devolver false
"youlookgreattoday" => no tiene en orden alfabético de sus secuencias, por lo devuelve false



Posible caso de uso

  • seguridad de la contraseña corrector
  • wordgame
  • ...

descargo de responsabilidad: deseo que ya tenía algo de código para mostrar a usted, pero yo, literalmente, no tienen nada aún.
Única cosa que se me ocurrió fue la de dividir la cadena en un array y hacer un poco de magia en la matriz ... pero aún así, me quedé atrapado.



Espero que uno de ustedes me va a ahorrar :)

15voto

ircmaxell Puntos 74865

Por lo tanto, vamos a empezar con un trivial de ejecución mediante un bucle y un contador (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;
}

Así que, ¿cómo funciona? Básicamente, recorre, y comprueba si el ord (número ascii) de que el personaje es uno más que el anterior. Si es así, aumenta el número de parámetro. De lo contrario, se establece en 1 (puesto que ya procesada ese carácter). Entonces, si $count es siempre mayor o igual a la cantidad solicitada, sabemos que tenemos que encontrar una secuencia, y puede volver...

Por lo tanto, 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, lo voy a devolver true para abcd y dcba...

Ahora, aquí tienes una muy sencilla solución:

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 hay que ir. Utilizamos la propiedad de que si sumamos un número decreciente para cada posición, secuencias consecutivas aparecerá el mismo número. Y eso es exactamente cómo funciona esto.

Y aquí está el mismo de la 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);
}

3voto

Salman A Puntos 60620
<?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"

3voto

ADev Puntos 330

Menos de bucle y si la 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;
  }

2voto

Second Rikudo Puntos 59550

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 cadena tiré en ella, y también tienes que elegir la cantidad de caracteres que desea contar! Yey!

1voto

newfurniturey Puntos 16866

Usted puede intentar el uso de PHP, ord() para obtener cada carácter ASCII del valor y iterar a través de su cadena de caracteres, la comparación de cada valor para encontrar las secuencias.

Esto puede ayudar a:

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 va a hacer es, va a iterar a través de la cadena, carácter por carácter. Se utilizará ord() para obtener la corriente de caracteres ASCII del valor y compararlo con el anterior valor de ASCII del carácter. Si están en secuencia, ya sea hacia adelante o a la inversa, se incrementa un contador. Cuando el contador hit 4, devuelve true!.

Esto coincidirá con avance y retroceso de la secuencia, así como ignorar caso. Así, abcd coinciden, aBcD , y también DcBa, entre otros!

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X