यदि कोई स्ट्रिंग T-SQL का उपयोग करके एक पैलिंड्रोम है तो परीक्षण करें


24

मैं टी-एसक्यूएल में एक शुरुआत कर रहा हूं। मैं यह तय करना चाहता हूं कि इनपुट स्ट्रिंग एक पैलिंड्रोम है, आउटपुट = 0 के साथ अगर यह नहीं है और आउटपुट = 1 है तो। मैं अभी भी वाक्य रचना का पता लगा रहा हूं। मुझे कोई त्रुटि संदेश भी नहीं मिल रहा है। मैं अलग-अलग समाधानों और कुछ प्रतिक्रिया की तलाश कर रहा हूं, ताकि टी-एसक्यूएल कैसे काम करता है, इसकी बेहतर समझ और ज्ञान प्राप्त करने के लिए, इस पर बेहतर बनने के लिए - मैं अभी भी एक छात्र हूं।

मुख्य विचार, जैसा कि मैं इसे देखता हूं, बाएं और दाएं- अधिकांश वर्णों की एक-दूसरे से तुलना करना है, समानता की जांच करना है, फिर बाएं से दूसरे चरित्र की तुलना दूसरे से पिछले-एक, आदि से करना है। हम एक लूप करते हैं: यदि वर्ण एक-दूसरे के बराबर हैं, तो हम जारी रखते हैं। यदि हम अंतिम छोर पर पहुंच गए हैं, तो हम 1 का उत्पादन करते हैं, यदि नहीं, तो हम 0 का उत्पादन करते हैं।

क्या आप समालोचना करेंगे:

CREATE function Palindrome(
    @String  Char
    , @StringLength  Int
    , @n Int
    , @Palindrome BIN
    , @StringLeftLength  Int
)
RETURNS Binary
AS
BEGIN
SET @ n=1
SET @StringLength= Len(String)

  WHILE @StringLength - @n >1

  IF
  Left(String,@n)=Right(String, @StringLength)

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

 RETURN @Binary =1

 ELSE RETURN @Palindrome =0

END

मुझे लगता है कि मैं सही रास्ते पर हूं, लेकिन मैं अभी भी बहुत दूर हूं। कोई विचार?


LTRIM(RTRIM(...))खाली स्थान के?
वर्नरसीडी

जवाबों:


60

यदि आप SQL सर्वर का उपयोग कर रहे हैं, तो आप जांच करने के लिए REVERSE () फ़ंक्शन का उपयोग कर सकते हैं ?

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

मार्टिन स्मिथ की टिप्पणी सहित, यदि आप SQL सर्वर 2012+ पर हैं तो आप IIF () फ़ंक्शन का उपयोग कर सकते हैं :

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

17

चूंकि समाधानों की एक उचित संख्या है मैं आपके प्रश्न के "समालोचक" भाग के साथ जाने वाला हूं। नोटों की एक जोड़ी: मैंने कुछ टाइपो तय किए हैं और नोट किया है कि मैंने कहाँ किया। अगर मैं उनके बारे में गलत हूं तो एक टाइपो टिप्पणी में इसका उल्लेख करें और मैं बताऊंगा कि क्या चल रहा है। मैं कई चीजों को इंगित करने जा रहा हूं जो आप पहले से ही जानते होंगे, इसलिए यदि मैंने किया तो कृपया अपराध न करें। कुछ टिप्पणियां अशुभ लग सकती हैं, लेकिन मुझे नहीं पता कि आप अपनी यात्रा में कहां हैं इसलिए यह मान लें कि आप अभी शुरुआत कर रहे हैं।

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

हमेशा एक charया varcharपरिभाषा के साथ लंबाई शामिल हैं । हारून बर्ट्रेंड यहां गहराई से बात करता है । वह बात कर रहा है, varcharलेकिन उसी के लिए जाता है charvarchar(255)अगर आप केवल अपेक्षाकृत छोटे तार चाहते हैं या शायद varchar(8000)बड़े लोगों के लिए या यहां तक ​​कि इसके लिए मैं इसका उपयोग करूंगा varchar(max)Varcharचर लंबाई के तार के charलिए केवल तय लोगों के लिए है। चूंकि आप स्ट्रिंग की लंबाई के बारे में सुनिश्चित नहीं हैं जो उपयोग में पारित हो रही है varchar। इसके अलावा यह binaryनहीं है bin

आगे आपको उन सभी चर को पैरामीटर के रूप में रखने की आवश्यकता नहीं है। उन्हें अपने कोड में घोषित करें। यदि आप इसे या बाहर पारित करने की योजना बनाते हैं, तो केवल पैरामीटर सूची में कुछ डालें। (आप देखेंगे कि यह अंत में कैसा दिखता है।) इसके अलावा आपके पास @StringLeftLength है लेकिन इसका उपयोग कभी न करें। इसलिए मैं इसे घोषित नहीं करने जा रहा हूं।

अगली चीज जो मैं करने जा रहा हूं, वह कुछ चीजों को स्पष्ट करने के लिए फिर से प्रारूपित करने की है।

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

यदि आप मेरे द्वारा किए गए इंडेंटिंग के तरीके को देखते हैं, तो आप देखेंगे कि मेरे पास यह है:

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

ऐसा इसलिए है क्योंकि कमांड WHILEऔर IFउनके बाद केवल पहली पंक्ति की कोड को प्रभावित करते हैं। BEGIN .. ENDयदि आप कई कमांड चाहते हैं तो आपको एक ब्लॉक का उपयोग करना होगा। इतना तय है कि हम मिल:

    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

आप देखेंगे कि मैंने केवल एक BEGIN .. ENDब्लॉक जोड़ा है IF। ऐसा इसलिए है क्योंकि भले ही IFबयान को कई पंक्तियों लंबा है (और यहां तक कि कई आदेशों शामिल हैं) यह अभी भी एक सिंगल स्टेटमेंट (सब कुछ कवर में प्रदर्शन किया है IFऔर ELSEबयान के कुछ भागों)।

आगे आपको अपने दोनों के बाद एक त्रुटि मिलेगी RETURNs। आप एक चर या एक शाब्दिक वापस कर सकते हैं। आप चर सेट नहीं कर सकते हैं और इसे उसी समय लौटा सकते हैं।

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

    RETURN @Palindrome

अब हम तर्क में हैं। पहले मुझे यह बताने दें कि आपके द्वारा उपयोग किए जा रहे कार्य LEFTऔर RIGHTकार्य महान हैं, लेकिन वे आपको अनुरोधित दिशा से आपके द्वारा दिए गए वर्णों की संख्या देने जा रहे हैं। तो चलिए आपको "परीक्षण" शब्द में पास करते हैं। पहली पास पर आपको यह प्राप्त होने वाला है (चर हटाते हुए):

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

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

जाहिर है कि आप क्या उम्मीद नहीं है। आप वास्तव में substringइसके बजाय उपयोग करना चाहते हैं । सबस्ट्रिंग आपको न केवल शुरुआती बिंदु बल्कि लंबाई से गुजरने देता है। तो आपको मिलेगा:

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

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

आगे आप अपने स्टेटमेंट में आपके द्वारा उपयोग किए जाने वाले वैरिएबल को केवल IF स्टेटमेंट की एक स्थिति में बढ़ा रहे हैं। पूरी तरह से उस संरचना से परिवर्तनशील चर को खींचो। इसके लिए एक अतिरिक्त BEGIN .. ENDब्लॉक की आवश्यकता होती है , लेकिन मुझे दूसरे को हटाने की जरूरत नहीं है।

        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

WHILEअंतिम परीक्षा के लिए आपको अपनी स्थिति बदलने की आवश्यकता है ।

        WHILE @StringLength > @n 

और अंतिम लेकिन कम से कम नहीं, जिस तरह से यह अब खड़ा है हम अंतिम चरित्र का परीक्षण नहीं करते हैं यदि विषम संख्या में वर्ण हैं। उदाहरण के लिए 'आना' का nपरीक्षण नहीं किया गया है। यह ठीक है, लेकिन यह मुझे एक अक्षर शब्द के लिए खाते की आवश्यकता है (यदि आप चाहते हैं कि यह एक सकारात्मक के रूप में गिना जाए)। तो हम यह कर सकते हैं कि मूल्य को सामने रखकर।

और अब हमारे पास आखिरकार है:

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

एक आखिरी टिप्पणी। मैं सामान्य रूप से प्रारूपण का बहुत बड़ा प्रशंसक हूं। यह वास्तव में आपको यह देखने में मदद कर सकता है कि आपका कोड कैसे काम करता है और संभावित गलतियों को इंगित करने में मदद करता है।

संपादित करें

जैसा कि स्फिंक्स ने उल्लेख किया है कि हमारे तर्क में अभी भी दोष है। एक बार जब हम हिट करते हैं ELSEऔर @Palindrome0 पर सेट होते हैं तो जारी रखने का कोई मतलब नहीं है। वास्तव में उस समय हम बस कर सकते थे RETURN

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

यह देखते हुए कि हम अब केवल @Palindrome"यह अभी भी संभव है यह एक पैलिंड्रोम है" के लिए उपयोग कर रहा है, वास्तव में इसका कोई मतलब नहीं है। हम परिवर्तनशील से छुटकारा पा सकते हैं और अपने तर्क को विफलता ( ) और (सकारात्मक प्रतिक्रिया) पर शॉर्ट सर्किट पर स्विच कर सकते हैं, अगर यह लूप के माध्यम से सभी तरह से बनाता है। आप देखेंगे कि यह वास्तव में कुछ हद तक हमारे तर्क को सरल करता है।RETURN 0RETURN 1

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

15

आप एक संख्या तालिका दृष्टिकोण का उपयोग भी कर सकते हैं।

यदि आपके पास पहले से कोई सहायक संख्या तालिका नहीं है, तो आप निम्नानुसार एक बना सकते हैं। यह एक लाख पंक्तियों के साथ आबाद है और इसलिए 2 मिलियन अक्षरों तक की स्ट्रिंग लंबाई के लिए अच्छा होगा।

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 

नीचे बाईं ओर प्रत्येक वर्ण की तुलना उसके दाईं ओर के साथी के साथ की जाती है, और यदि कोई विसंगतियां पाई जाती हैं, तो शॉर्ट सर्किट हो सकती है और वापस लौट सकती है। 0. यदि स्ट्रिंग एक विषम लंबाई है, तो मध्य वर्ण की जाँच नहीं की जाती है क्योंकि यह परिणाम में परिवर्तन नहीं करेगा। ।

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 

यदि आप सुनिश्चित नहीं हैं कि यह कैसे काम करता है तो आप नीचे से देख सकते हैं

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; 

यहाँ छवि विवरण दर्ज करें

यह मूल रूप से एक ही एल्गोरिदम है जैसा कि प्रश्न में वर्णित है, लेकिन पुनरावृत्त प्रक्रियात्मक कोड के बजाय एक सेट आधारित तरीके से किया गया है।


12

REVERSE()विधि "सुधार", यानी स्ट्रिंग का केवल आधा पीछे:

SELECT CASE WHEN RIGHT(@string, LEN(@string)/2) 
                 = REVERSE(LEFT(@string, LEN(@string)/2)) 
            THEN 1 ELSE 0 END AS Palindrome;

मुझे कुछ अजीब होने की उम्मीद नहीं है अगर स्ट्रिंग में विषम संख्या में वर्ण हैं; मध्य चरित्र की जाँच नहीं की जानी चाहिए।


@Hvd द्वारा एक टिप्पणी उठाई गई थी कि यह सभी टकरावों में सरोगेट जोड़े को सही ढंग से संभाल नहीं सकता है।

@srzzky ने टिप्पणी की कि यह सप्लीमेंट्री कैरेक्टर / सरोगेट पेयर को उसी तरीके से हैंडल करता है, जिस तरह से REVERSE()वे केवल तभी ठीक से काम करते हैं, जब करंट डेटाबेस का डिफॉल्ट कोलेशन खत्म हो जाता है _SC


8

उपयोग किए बिना REVERSE, जो तुरंत मन में आता है, लेकिन अभी भी एक फ़ंक्शन 1 का उपयोग कर रहा है ; मैं निम्नलिखित की तरह कुछ का निर्माण होगा।

यह हिस्सा केवल मौजूदा फ़ंक्शन को हटा देता है, अगर यह पहले से मौजूद है:

IF OBJECT_ID('dbo.IsPalindrome') IS NOT NULL
DROP FUNCTION dbo.IsPalindrome;
GO

यह स्वयं कार्य है:

CREATE FUNCTION dbo.IsPalindrome
(
    @Word NVARCHAR(500)
) 
RETURNS BIT
AS
BEGIN
    DECLARE @IsPalindrome BIT;
    DECLARE @LeftChunk NVARCHAR(250);
    DECLARE @RightChunk NVARCHAR(250);
    DECLARE @StrLen INT;
    DECLARE @Pos INT;

    SET @RightChunk = '';
    SET @IsPalindrome = 0;
    SET @StrLen = LEN(@Word) / 2;
    IF @StrLen % 2 = 1 SET @StrLen = @StrLen - 1;
    SET @Pos = LEN(@Word);
    SET @LeftChunk = LEFT(@Word, @StrLen);

    WHILE @Pos > (LEN(@Word) - @StrLen)
    BEGIN
        SET @RightChunk = @RightChunk + SUBSTRING(@Word, @Pos, 1)
        SET @Pos = @Pos - 1;
    END

    IF @LeftChunk = @RightChunk SET @IsPalindrome = 1;
    RETURN (@IsPalindrome);
END
GO

यहां, हम फ़ंक्शन का परीक्षण करते हैं:

IF dbo.IsPalindrome('This is a word') = 1 
    PRINT 'YES'
ELSE
    PRINT 'NO';

IF dbo.IsPalindrome('tattarrattat') = 1 
    PRINT 'YES'
ELSE
    PRINT 'NO';

यह शब्द के पहले आधे भाग की तुलना शब्द के अंतिम आधे के विपरीत ( REVERSEफ़ंक्शन का उपयोग किए बिना ) करता है। यह कोड ठीक से विषम और लंबाई दोनों शब्दों को संभालता है। पूरे शब्द के माध्यम से लूप करने के बजाय, हम सीधे शब्द LEFTके पहले आधे भाग को प्राप्त करते हैं, फिर सही आधे के उल्टे हिस्से को प्राप्त करने के लिए शब्द के अंतिम आधे भाग के माध्यम से लूप करते हैं। यदि शब्द एक विषम-लंबाई है, तो हम बीच के अक्षर को छोड़ देते हैं, क्योंकि परिभाषा के अनुसार यह दोनों "हिस्सों" के लिए समान होगा।


1 - फ़ंक्शन बहुत धीमा हो सकता है!


6

REVERSE का उपयोग किए बिना ... एक पुनरावर्ती समाधान का उपयोग करना हमेशा मज़ेदार होता है;) (मैंने SQL सर्वर 2012 में मेरा काम किया था, पहले के संस्करणों में पुनरावृत्ति की सीमाएँ हो सकती हैं)

create function dbo.IsPalindrome (@s varchar(max)) returns bit
as
begin
    return case when left(@s,1) = right(@s,1) then case when len(@s) < 3 then 1 else dbo.IsPalindrome(substring(@s,2,len(@s)-2)) end else 0 end;
end;
GO

select dbo.IsPalindrome('a')
1
select dbo.IsPalindrome('ab')
0
select dbo.IsPalindrome('bab')
1
select dbo.IsPalindrome('gohangasalamiimalasagnahog')
1

6

यह मार्टिन स्मिथ के सेट-बेस्ड सॉल्यूशन का एक इनलाइन टीवीएफ-फ्रेंडली वर्जन है , इसके अलावा एक-दो सुपरफुल एन्हांसमेंट से सजाया गया है:

WITH Nums AS
(
  SELECT
    N = number
  FROM
    dbo.Numbers WITH(FORCESEEK) /*Requires a suitably indexed numbers table*/
)
SELECT
  IsPalindrome =
    CASE
      WHEN EXISTS
      (
        SELECT *
        FROM Nums
        WHERE N <= L / 2
          AND SUBSTRING(S, N, 1) <> SUBSTRING(S, 1 + L - N, 1)
      )
      THEN 0
      ELSE 1
    END
FROM
  (SELECT LTRIM(RTRIM(@Candidate)), LEN(@Candidate)) AS v (S, L)
;

5

बस मज़े के लिए, यहाँ एक SQL Server 2016 स्केलर यूज़र-डिफ़ाइंड फ़ंक्शन इन-मेमोरी ओएलटीपी फ़ीचर के साथ है:

ALTER FUNCTION dbo.IsPalindrome2 ( @inputString NVARCHAR(500) )
RETURNS BIT
WITH NATIVE_COMPILATION, SCHEMABINDING
AS
BEGIN ATOMIC WITH (TRANSACTION ISOLATION LEVEL = SNAPSHOT, LANGUAGE = N'English')

    DECLARE @i INT = 1, @j INT = LEN(@inputString)

    WHILE @i < @j
    BEGIN
        IF SUBSTRING( @inputString, @i, 1 ) != SUBSTRING( @inputString, @j, 1 )
        BEGIN
            RETURN(0)
        END
        ELSE
            SELECT @i+=1, @j-=1

    END

    RETURN(1)

END
GO

4

एक बड़ा मुद्दा जो आप चलाने जा रहे हैं, वह यह है कि 1 से अधिक किसी भी मान के साथ, LEFTया RIGHTउस स्थान पर वर्ण नहीं, बल्कि कई वर्णों को लौटाएगा। यदि आप परीक्षण की इस पद्धति के साथ रखना चाहते हैं, तो इसे संशोधित करने का एक बहुत सरल तरीका होगा

RIGHT(LEFT(String,@n),1)=LEFT(RIGHT(String, @StringLength),1)

यह हमेशा बाएं स्ट्रिंग के सबसे दाहिने वर्ण और दाएँ स्ट्रिंग के सबसे बाएँ वर्ण को पकड़ता है।

शायद यह जांचने के लिए एक कम गोल चक्कर रास्ता, हालांकि, इसका उपयोग करना होगा SUBSTRING:

SUBSTRING(String, @n, 1) = SUBSTRING(String, ((LEN(String) - @n) + 1), 1)

ध्यान दें कि SUBSTRING1-अनुक्रमित है, इसलिए + 1में ((LEN(String) - @n) + 1)

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.