Saltar al contenido

Prueba si un string es un palíndromo usando T-SQL

Recabamos en internet y así tener para ti la solución para tu duda, si continúas con preguntas puedes dejar la duda y contestaremos porque estamos para ayudarte.

Solución:

Si está usando SQL Server, puede usar la función REVERSE () para verificar.

SELECT CASE WHEN @string = REVERSE(@String) THEN 1 ELSE 0 END AS Palindrome;

Incluyendo el comentario de Martin Smith, si está en SQL Server 2012+ puede usar la función IIF ():

SELECT IIF(@string = REVERSE(@String),1,0) AS Palindrome;

Dado que hay un buen número de soluciones, voy a ir con la parte de “crítica” de su pregunta. Un par de notas: He corregido algunos errores tipográficos y he anotado dónde lo hice. Si me equivoco acerca de que es un error tipográfico, menciónalo en los comentarios y te explicaré lo que está pasando. Voy a señalar varias cosas que quizás ya sepas, así que no te ofendas si lo hice. Algunos comentarios pueden parecer exigentes, pero no sé dónde se encuentra en su viaje, así que debe asumir que recién está comenzando.

CREATE function Palindrome (
    @String  Char
    , @StringLength  Int
    , @n Int
    , @Palindrome BIN
    , @StringLeftLength  Int

SIEMPRE incluir la longitud con un char o varchar definición. Aaron Bertrand habla de ello en profundidad aquí. El esta hablando de varchar pero lo mismo vale para char. Usaría un varchar(255) para esto si solo desea cadenas relativamente cortas o tal vez un varchar(8000) para los más grandes o incluso varchar(max). Varchar es para cadenas de longitud variable char es solo para fijos. Como no está seguro de la longitud de string siendo pasado en uso varchar. También es binary no bin.

A continuación, no es necesario poner todas esas variables como parámetros. Declararlos dentro de su código. Solo ponga algo en la lista de parámetros si planea pasarlo dentro o fuera. (Verá cómo se ve esto al final). También tiene @StringLeftLength pero nunca lo use. Entonces no lo voy a declarar.

Lo siguiente que voy a hacer es volver a formatear un poco para que algunas cosas sean obvias.

BEGIN
    SET @n=1
    SET @StringLength = Len(@String) -- Missed an @

    WHILE @StringLength - @n >1 
        IF Left(@String,@n)=Right(@String, @StringLength) -- More missing @s
            SET @n = @n + 1 -- Another missing @

    SET @StringLength = @StringLength - 1  -- Watch those @s :)

    RETURN @Palindrome = 1 -- Assuming another typo here 

    ELSE 
        RETURN @Palindrome =0

END

Si miras la forma en que hice la sangría, notarás que tengo esto:

    WHILE @StringLength - @n >1 
        IF Left(@String,@n)=Right(@String, @StringLength)
            SET @n = @n + 1

Eso es porque comandos como WHILE y IF solo afectan a la primera línea de código después de ellos. Tienes que usar un BEGIN .. END bloquear si desea varios comandos. Así que arreglando que obtenemos:

    WHILE @StringLength - @n > 1 
        IF Left(@String,@n)=Right(@String, @StringLength)
            BEGIN 
                SET @n = @n + 1
                SET @StringLength = @StringLength - 1
                RETURN @Palindrome = 1 
            END
        ELSE 
            RETURN @Palindrome = 0

Notarás que solo agregué un BEGIN .. END bloque en el IF. Eso es porque a pesar de que el IF La declaración tiene varias líneas de longitud (e incluso contiene varios comandos) sigue siendo una sola declaración (que cubre todo lo que se realiza en el IF y el ELSE partes de la declaración).

A continuación, obtendrá un error después de que ambos RETURNs. Puede devolver una variable O un literal. No puede establecer la variable y devolverla al mismo tiempo.

                SET @Palindrome = 1 
            END
        ELSE 
            SET @Palindrome = 0

    RETURN @Palindrome

Ahora estamos en la lógica. Primero permítame señalar que el LEFT y RIGHT Las funciones que está utilizando son excelentes, pero le darán la cantidad de caracteres que ingresa desde la dirección solicitada. Así que digamos que pasó la palabra “prueba”. En la primera pasada, obtendrá esto (eliminando variables):

LEFT('test',1) = RIGHT('test',4)
    t          =      test

LEFT('test',2) = RIGHT('test',3)
    te         =      est

Obviamente eso no es lo que esperabas. Realmente querrías usar substring en lugar de. La subcadena le permite pasar no solo el punto de inicio sino también la longitud. Entonces obtendrías:

SUBSTRING('test',1,1) = SUBSTRING('test',4,1)
         t            =         t

SUBSTRING('test',2,1) = SUBSTRING('test',3,1)
         e            =         s

A continuación, está incrementando las variables que usa en su ciclo solo en una condición de la declaración IF. Saque la variable que se incrementa fuera de esa estructura por completo. Eso va a requerir un adicional BEGIN .. END bloquear, pero puedo eliminar el otro.

        WHILE @StringLength - @n > 1 
            BEGIN
                IF SUBSTRING(@String,@n,1) = SUBSTRING(@String, @StringLength,1)
                    SET @Palindrome = 1 
                ELSE 
                    SET @Palindrome = 0

                SET @n = @n + 1
                SET @StringLength = @StringLength - 1
            END

Necesitas cambiar tu WHILE condición para permitir la última prueba.

        WHILE @StringLength > @n 

Y por último, pero no menos importante, tal como está ahora, no probamos el último carácter si hay un número impar de caracteres. Por ejemplo con ‘ana’ el n no se prueba. Eso está bien, pero a mí me parece bien, tenemos que dar cuenta de una palabra de una sola letra (si quieres que cuente como un positivo, claro). Entonces podemos hacer eso configurando el valor por adelantado.

Y ahora finalmente tenemos:

CREATE FUNCTION Palindrome (@String  varchar(255)) 
RETURNS Binary
AS

    BEGIN
        DECLARE @StringLength  Int
            , @n Int
            , @Palindrome binary

        SET @n = 1
        SET @StringLength = Len(@String)
        SET @Palindrome = 1

        WHILE @StringLength > @n 
            BEGIN
                IF SUBSTRING(@String,@n,1) = SUBSTRING(@String, @StringLength,1)
                    SET @Palindrome = 1 
                ELSE 
                    SET @Palindrome = 0

                SET @n = @n + 1
                SET @StringLength = @StringLength - 1
            END
        RETURN @Palindrome
    END

Un ultimo comentario. Soy un gran fanático del formateo en general. Realmente puede ayudarlo a ver cómo funciona su código y ayudarlo a señalar posibles errores.

Editar

Como mencionó Sphinxxx, todavía tenemos una falla en nuestra lógica. Una vez que golpeamos el ELSE y establecer @Palindrome a 0 no tiene sentido continuar. De hecho, en ese momento podríamos RETURN.

                IF SUBSTRING(@String,@n,1) = SUBSTRING(@String, @StringLength,1)
                    SET @Palindrome = 1 
                ELSE 
                    RETURN 0

Dado que ahora solo estamos usando @Palindrome porque “todavía es posible que esto sea un palíndromo”, realmente no tiene sentido tenerlo. Podemos deshacernos de la variable y cambiar nuestra lógica a cortocircuito en caso de falla (el RETURN 0) y RETURN 1 (una respuesta positiva) solo si llega hasta el final del ciclo. Notarás que esto en realidad simplifica un poco nuestra lógica.

CREATE FUNCTION Palindrome (@String  varchar(255)) 
RETURNS Binary
AS

    BEGIN
        DECLARE @StringLength  Int
            , @n Int

        SET @n = 1
        SET @StringLength = Len(@String)

        WHILE @StringLength > @n 
            BEGIN
                IF SUBSTRING(@String,@n,1) <> SUBSTRING(@String, @StringLength,1)
                    RETURN 0

                SET @n = @n + 1
                SET @StringLength = @StringLength - 1
            END
        RETURN 1
    END

También puede utilizar un método de tabla de números.

Si aún no tiene una tabla de números auxiliares, puede crear una de la siguiente manera. Esto se llena con un millón de filas y, por lo tanto, será bueno para string longitudes de hasta 2 millones de caracteres.

CREATE TABLE dbo.Numbers (number int PRIMARY KEY);

INSERT INTO dbo.Numbers
            (number)
SELECT TOP 1000000 ROW_NUMBER() OVER (ORDER BY @@SPID)
FROM   master..spt_values v1,
       master..spt_values v2 

A continuación se compara cada carácter de la izquierda con su socio correspondiente de la derecha, y si se encuentran discrepancias, se puede producir un cortocircuito y devolver 0. Si el string es una longitud impar, el carácter del medio no está marcado ya que esto no alterará el resultado.

DECLARE @Candidate VARCHAR(MAX) = 'aibohphobia'; /*the irrational fear of palindromes.*/

SET @Candidate = LTRIM(RTRIM(@Candidate)); /*Ignoring any leading or trailing spaces. 
                      Could use `DATALENGTH` instead of `LEN` if these are significant*/

SELECT CASE
         WHEN EXISTS (SELECT *
                      FROM   dbo.Numbers
                      WHERE  number <= LEN(@Candidate) / 2
                             AND SUBSTRING(@Candidate, number, 1) 
                              <> SUBSTRING(@Candidate, 1 + LEN(@Candidate) - number, 1))
           THEN 0
         ELSE 1
       END AS IsPalindrome 

Si no está seguro de cómo funciona, puede verlo a continuación.

DECLARE @Candidate VARCHAR(MAX) = 'this is not a palindrome';

SELECT SUBSTRING(@Candidate, number, 1)                       AS [Left],
       SUBSTRING(@Candidate, 1 + LEN(@Candidate) - number, 1) AS [Right]
FROM   dbo.Numbers
WHERE  number <= LEN(@Candidate) / 2; 

ingrese la descripción de la imagen aquí

Este es básicamente el mismo algoritmo que se describe en la pregunta, pero se realiza de una manera basada en conjuntos en lugar de un código de procedimiento iterativo.

Te mostramos comentarios y valoraciones

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *