"] []" वाइल्डकार्ड का उपयोग करके PATINDEX के साथ एक] (समापन वर्ग ब्रैकेट) का मिलान करना


9

मैं T-SQL में एक कस्टम JSON पार्सर लिख रहा हूँ

अपने पार्सर के उद्देश्य के लिए, मैं उस PATINDEXफ़ंक्शन का उपयोग कर रहा हूं जो टोकन की सूची से टोकन की स्थिति की गणना करता है। मेरे मामले में टोकन सभी एकल वर्ण हैं और इनमें ये शामिल हैं:

{} []:,

आमतौर पर, जब मुझे किसी दिए गए पात्रों में से किसी एक की पहली (पहली) स्थिति को खोजने की आवश्यकता होती है, तो मैं PATINDEXइस तरह से फ़ंक्शन का उपयोग करता हूं :

PATINDEX('%[abc]%', SourceString)

समारोह तो मुझे के पहले की स्थिति दे देंगे aया bया cमें - जो भी पहले हो पाया होता है - SourceString

अब मेरे मामले में समस्या ]चरित्र से जुड़ी हुई प्रतीत होती है । जैसे ही मैं इसे चरित्र सूची में निर्दिष्ट करता हूं, जैसे:

PATINDEX('%[[]{}:,]%', SourceString)

मेरा इरादा पैटर्न स्पष्ट रूप से टूट जाता है, क्योंकि फ़ंक्शन कभी भी मैच नहीं पाता है। ऐसा लगता है कि मुझे पहले से बचने का एक तरीका चाहिए ]ताकि PATINDEXइसे एक विशेष प्रतीक के बजाय लुकअप पात्रों में से एक माना जाए।

मैंने इस सवाल को एक समान समस्या के बारे में पूछा है:

हालांकि, उस मामले में ]बस कोष्ठक में निर्दिष्ट करने की आवश्यकता नहीं है, क्योंकि यह सिर्फ एक चरित्र है और इसे उनके चारों ओर कोष्ठक के बिना निर्दिष्ट किया जा सकता है। वैकल्पिक समाधान, जो भागने का उपयोग करता है, केवल इसके लिए काम करता है LIKEऔर इसके लिए नहीं PATINDEX, क्योंकि यह एक ESCAPEउपवर्ग का उपयोग करता है, पूर्व द्वारा समर्थित और बाद के द्वारा नहीं।

तो, मेरे सवाल है, वहाँ किसी भी तरह से एक के लिए देखने के लिए है ]के साथ PATINDEXका उपयोग कर [ ]वाइल्डकार्ड? या अन्य ट्रांसेक्ट-एसक्यूएल टूल्स का उपयोग करके उस कार्यक्षमता का अनुकरण करने का एक तरीका है?

अतिरिक्त जानकारी

यहां एक क्वेरी का उदाहरण दिया गया है, जहां मुझे ऊपर दिए PATINDEXगए […]पैटर्न के साथ उपयोग करने की आवश्यकता है । यहां पैटर्न काम करता है (यद्यपि कुछ हद तक ) क्योंकि इसमें ]चरित्र शामिल नहीं है । मुझे इसके साथ काम करने की आवश्यकता है ]:

WITH
  data AS (SELECT CAST('{"f1":["v1","v2"],"f2":"v3"}' AS varchar(max)) AS ResponseJSON),
  parser AS
  (
    SELECT
      Level         = 1,
      OpenClose     = 1,
      P             = p.P,
      S             = SUBSTRING(d.ResponseJSON, 1, NULLIF(p.P, 0) - 1),
      C             = SUBSTRING(d.ResponseJSON, NULLIF(p.P, 0), 1),
      ResponseJSON  = SUBSTRING(d.ResponseJSON, NULLIF(p.P, 0) + 1, 999999)
    FROM
      data AS d
      CROSS APPLY (SELECT PATINDEX('%[[{]%', d.ResponseJSON)) AS p (P)
    UNION ALL
    SELECT
      Level         = ISNULL(d.OpenClose - 1, 0) + d.Level + ISNULL(oc.OpenClose, 0),
      OpenClose     = oc.OpenClose,
      P             = d.P + p.P,
      S             = SUBSTRING(d.ResponseJSON, 1, NULLIF(p.P, 0) - 1),
      C             = c.C,
      ResponseJSON  = SUBSTRING(d.ResponseJSON, NULLIF(p.P, 0) + 1, 999999)
    FROM
      parser AS d
      CROSS APPLY (SELECT PATINDEX('%[[{}:,]%' COLLATE Latin1_General_BIN2, d.ResponseJSON)) AS p (P)
      CROSS APPLY (SELECT SUBSTRING(d.ResponseJSON, NULLIF(p.P, 0), 1)) AS c (C)
      CROSS APPLY (SELECT CASE WHEN c.C IN ('[', '{') THEN 1 WHEN c.C IN (']', '}') THEN 0 END) AS oc (OpenClose)
    WHERE 1=1
      AND p.P <> 0
  )
SELECT
  *
FROM
  parser
OPTION
  (MAXRECURSION 0)
;

मुझे जो आउटपुट मिलता है वह है:

Level  OpenClose  P   S      C   ResponseJSON
-----  ---------  --  -----  --  ---------------------------
1      1          1          {   "f1":["v1","v2"],"f2":"v3"}
1      null       6   "f1"   :   ["v1","v2"],"f2":"v3"}
2      1          7          [   "v1","v2"],"f2":"v3"}
2      null       12  "v1"   ,   "v2"],"f2":"v3"}
2      null       18  "v2"]  ,   "f2":"v3"}
2      null       23  "f2"   :   "v3"}
2      0          28  "v3"   }   

आप देख सकते हैं कि इसे पंक्तियों में से एक के ]भाग के रूप में शामिल किया गया है SLevelस्तंभ, घोंसले ब्रैकेट अर्थ और ब्रेसिज़ नेस्टिंग के स्तर को दर्शाता है। जैसा कि आप देख सकते हैं, एक बार स्तर 2 हो जाने के बाद, यह कभी भी 1 पर नहीं लौटता है। ऐसा होता अगर मैं टोकन के रूप में PATINDEXपहचान बना पाता ]

उपरोक्त उदाहरण के लिए अपेक्षित आउटपुट है:

Level  OpenClose  P   S     C   ResponseJSON
-----  ---------  --  ----  --  ---------------------------
1      1          1         {   "f1":["v1","v2"],"f2":"v3"}
1      NULL       6   "f1"  :   ["v1","v2"],"f2":"v3"}
2      1          7         [   "v1","v2"],"f2":"v3"}
2      NULL       12  "v1"  ,   "v2"],"f2":"v3"}
2      0          17  "v2"  ]   ,"f2":"v3"}
1      NULL       18        ,   "f2":"v3"}
1      NULL       23  "f2"  :   "v3"}
1      0          28  "v3"  }

आप इस क्वेरी के साथ db <> फिडल पर खेल सकते हैं ।


हम एसक्यूएल सर्वर 2014 का उपयोग कर रहे हैं और जल्द ही एक संस्करण में अपग्रेड करने की संभावना नहीं है जो जेन्स को पार्सिंग का समर्थन करता है। मैं काम करने के लिए एक आवेदन लिख सकता था, लेकिन पार्सिंग के परिणामों को आगे संसाधित करने की आवश्यकता है, जो कि केवल पार्सिंग की तुलना में आवेदन में अधिक काम का अर्थ है - उस तरह का काम जो बहुत आसान होगा, और शायद अधिक कुशलता से, के साथ किया गया एक टी-एसक्यूएल स्क्रिप्ट, अगर केवल मैं इसे सीधे परिणामों पर लागू कर सकता हूं।

यह बहुत कम संभावना है कि मैं इस समस्या के समाधान के रूप में SQLCLR का उपयोग कर सकता हूं। हालांकि, मुझे कोई आपत्ति नहीं है अगर कोई SQLCLR समाधान पोस्ट करने का फैसला करता है, क्योंकि यह दूसरों के लिए उपयोगी हो सकता है।


जोसन कैसा दिखता है ["foo]bar”]?
सलमान ए

@ सलमान: ऐसे परिदृश्यों को सुरक्षित रूप से अनदेखा किया जा सकता है।
एंड्री एम

जवाबों:


6

मेरा स्वयं का समाधान, जो वर्कअराउंड का अधिक है, जिसमें वर्ण श्रृंखला को निर्दिष्ट करना शामिल है जिसमें वाइल्डकार्ड ]में अन्य वर्णों के साथ उस सीमा को शामिल करना और उपयोग करना शामिल है [ ]। मैंने ASCII तालिका पर आधारित एक सीमा का उपयोग किया। उस तालिका के अनुसार, ]चरित्र निम्नलिखित पड़ोस में स्थित है:

हेक्स दिसंबर चार
--- --- ----
...
5 ए 90 जेड
5 बी 91 [
5C 92 \
5 डी 93]
5 ई 94 ^
5F 95 _
...

मेरे रेंज है, इसलिए, के रूप ले लिया [-^, यानी यह चार अक्षर शामिल हैं: [, \, ], ^। मैंने यह भी निर्दिष्ट किया कि पैटर्न ASCII रेंज से बिल्कुल मेल खाने के लिए एक बाइनरी कोलैशन का उपयोग करता है। परिणामी PATINDEXअभिव्यक्ति इस तरह दिख रही है:

PATINDEX('%[[-^{}:,]%' COLLATE Latin1_General_BIN2, MyJSONString)

इस दृष्टिकोण के साथ स्पष्ट समस्या यह है कि पैटर्न की शुरुआत में सीमा में दो अवांछित वर्ण शामिल हैं, \और ^। समाधान ने मेरे लिए सिर्फ इसलिए काम किया क्योंकि अतिरिक्त वर्ण कभी भी उस विशिष्ट JSON स्ट्रिंग्स में नहीं हो सकते थे जिनकी मुझे पार्स करने की आवश्यकता थी। स्वाभाविक रूप से, यह सामान्य रूप से सच नहीं हो सकता है, इसलिए मुझे अभी भी अन्य तरीकों में दिलचस्पी है, उम्मीद है कि मेरी तुलना में अधिक सार्वभौमिक है।


4

जब मेरा बहुत स्ट्रगल बंटवारा करना होता है तो मुझे इस पर शायद बहुत बुरा लगता है।

यदि आपके पास वर्णों का ज्ञात सेट है, तो उनकी एक तालिका बनाएं।

CREATE TABLE dbo.characters ( character CHAR(1) NOT NULL PRIMARY KEY CLUSTERED );

INSERT dbo.characters ( character )
SELECT *
FROM (
        SELECT '[' UNION ALL
        SELECT ']' UNION ALL
        SELECT '{' UNION ALL
        SELECT '}' UNION ALL
        SELECT ',' 
) AS x (v)

तब उस जादुई का उपयोग CROSS APPLYके साथ CHARINDEX:

SELECT TOP 1000 p.Id, p.Body, ca.*
FROM dbo.Posts AS p
CROSS APPLY (
    SELECT TOP 1 CHARINDEX(c.character, p.Body) AS first_things_first
    FROM dbo.characters AS c
    ORDER BY CHARINDEX(c.character, p.Body) ASC
) AS ca
WHERE ca.first_things_first > 0

अगर मुझे कुछ स्पष्ट याद आ रहा है कि आपको क्या करने की आवश्यकता है, तो मुझे पता है।


4

मैंने खोज से पहले अपमानजनक चरित्र को बदलने के लिए अतीत में दृष्टिकोण देखा है, और बाद में इसे वापस रखा है।

इस मामले में हम कुछ ऐसा कर सकते हैं:

DECLARE @test NVARCHAR(MAX);
DECLARE @replacementcharacter CHAR(1) = CHAR(174);

SET @test = 'Test[]@String'

SELECT PATINDEX('%[[' + @replacementcharacter + '@]%', REPLACE(@test,']',@Replacementcharacter))

यह कोड सही ढंग से रिटर्न करता है। मैं as वर्ण का उपयोग कर रहा हूं क्योंकि यह दिखाई देने की संभावना नहीं है - यदि कोई ASCII वर्ण नहीं हैं जो आप उपयोग नहीं करेंगे, तो यह समाधान काम नहीं करेगा।

अजीब तरह से हालांकि, आपके सवाल का सीधा जवाब होगा - मुझे या तो ']' 'की खोज करने के लिए PATINDEX नहीं मिल सकता है, लेकिन यदि आप इसे बदलते हैं तो आपको इसकी आवश्यकता नहीं है।

एक ही उदाहरण लेकिन चर उपयोग के बिना:

DECLARE @test NVARCHAR(MAX);

SET @test = 'Test[]@String'

SELECT PATINDEX('%[[' + CHAR(174) + '@]%', REPLACE(@test,']',CHAR(174)))

अपने कोड में उपरोक्त समाधान का उपयोग करने से आपके आवश्यक परिणाम मिलते हैं:

WITH
  data AS (SELECT CAST('{"f1":["v1","v2"],"f2":"v3"}' AS varchar(max)) AS ResponseJSON),
  parser AS
  (
    SELECT
      Level         = 1,
      OpenClose     = 1,
      P             = p.P,
      S             = SUBSTRING(d.ResponseJSON, 1, NULLIF(p.P, 0) - 1),
      C             = SUBSTRING(d.ResponseJSON, NULLIF(p.P, 0), 1),
      ResponseJSON  = SUBSTRING(d.ResponseJSON, NULLIF(p.P, 0) + 1, 999999)
    FROM
      data AS d
      CROSS APPLY (SELECT PATINDEX('%[[{'+ CHAR(174) + ']%', REPLACE(d.ResponseJSON,']',CHAR(174)))) AS p (P)
    UNION ALL
    SELECT
      Level         = ISNULL(d.OpenClose - 1, 0) + d.Level + ISNULL(oc.OpenClose, 0),
      OpenClose     = oc.OpenClose,
      P             = d.P + p.P,
      S             = SUBSTRING(d.ResponseJSON, 1, NULLIF(p.P, 0) - 1),
      C             = c.C,
      ResponseJSON  = SUBSTRING(d.ResponseJSON, NULLIF(p.P, 0) + 1, 999999)
    FROM
      parser AS d
      CROSS APPLY (SELECT PATINDEX('%[[{}:,'+ CHAR(174) + ']%' COLLATE Latin1_General_BIN2, REPLACE(d.ResponseJSON,']',CHAR(174)))) AS p (P)
      CROSS APPLY (SELECT SUBSTRING(d.ResponseJSON, NULLIF(p.P, 0), 1)) AS c (C)
      CROSS APPLY (SELECT CASE WHEN c.C IN ('[', '{') THEN 1 WHEN c.C IN (']', '}') THEN 0 END) AS oc (OpenClose)
    WHERE 1=1
      AND p.P <> 0
  )
SELECT
  *
FROM
  parser
OPTION
  (MAXRECURSION 0)
;

4

चूंकि ]केवल विशेष में है [...], आप PATINDEXदो बार उपयोग कर सकते हैं , ]बाहर की ओर बढ़ रहे हैं [...]। दोनों का मूल्यांकन PATINDEX('%[[{}:,]%', SourceString)और PATINDEX('%]%', SourceString)। यदि एक परिणाम शून्य है, तो दूसरे को लें। अन्यथा, दो मूल्यों का कम लें।

आपके उदाहरण में:

WITH
  data AS (SELECT CAST('{"f1":["v1","v2"],"f2":"v3"}' AS varchar(max)) AS ResponseJSON),
  parser AS
  (
    SELECT
      Level         = 1,
      OpenClose     = 1,
      P             = p.P,
      S             = SUBSTRING(d.ResponseJSON, 1, NULLIF(p.P, 0) - 1),
      C             = SUBSTRING(d.ResponseJSON, NULLIF(p.P, 0), 1),
      ResponseJSON  = SUBSTRING(d.ResponseJSON, NULLIF(p.P, 0) + 1, 999999)
    FROM
      data AS d
      CROSS APPLY (SELECT PATINDEX('%[[{]%', d.ResponseJSON)) AS p (P)
    UNION ALL
    SELECT
      Level         = ISNULL(d.OpenClose - 1, 0) + d.Level + ISNULL(oc.OpenClose, 0),
      OpenClose     = oc.OpenClose,
      P             = d.P + ISNULL(p.P, 0),
      S             = SUBSTRING(d.ResponseJSON, 1, p.P - 1),
      C             = c.C,
      ResponseJSON  = SUBSTRING(d.ResponseJSON, p.P + 1, 999999)
    FROM
      parser AS d
      CROSS APPLY (VALUES (NULLIF(PATINDEX('%[[{}:,]%', d.ResponseJSON), 0), NULLIF(PATINDEX('%]%', d.ResponseJSON), 0))) AS p_ (a, b)
      CROSS APPLY (VALUES (CASE WHEN p_.a < p_.b OR p_.b IS NULL THEN p_.a ELSE p_.b END)) AS p (P)
      CROSS APPLY (SELECT SUBSTRING(d.ResponseJSON, p.P, 1)) AS c (C)
      CROSS APPLY (SELECT CASE WHEN c.C IN ('[', '{') THEN 1 WHEN c.C IN (']', '}') THEN 0 END) AS oc (OpenClose)
    WHERE 1=1
      AND p.P <> 0
  )
SELECT
  *
FROM
  parser
OPTION
  (MAXRECURSION 0)
;

https://dbfiddle.uk/?rdbms=sqlserver_2014&fiddle=66fba2218d8d7d310d5a682be143f6eb


-4

बाईं ओर '[' के लिए:

PATINDEX('%[[]%',expression)

एक सही ']' 'के लिए:

PATINDEX('%]%',expression)

1
यह निर्दिष्ट करता है कि या तो एक उद्घाटन वर्ग ब्रैकेट, या एक समापन के लिए कैसे खोजा जाए; ओपी एक समापन वर्ग ब्रैकेट सहित कई पात्रों में से एक की तलाश कर रहा है (वर्ग कोष्ठक में विचाराधीन पात्रों को संलग्न करके)।
RDFozz
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.