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;
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.