Esiste un equivalente T-SQL per la punteggiatura come [0-9] è per i numeri e [az] è per le lettere?


8

Esiste un equivalente T-SQL dei modelli [0-9]e [a-z]che mi consentirà di estrarre i valori da una colonna che contiene la punteggiatura?

Per esempio:

Create Table #Test
(
Value   VarChar(10)
) 
Insert Into #Test
Values ('123a'), ('456b'), ('12ABC'),('AB!23'),('C?D789')

Select      *
From        #Test
Where       Value like '[0-9][0-9][0-9][a-z]'

Ciò restituirebbe valori in cui i primi 3 caratteri sono numeri compresi tra 0 e 9 e l'ultimo carattere sarà una lettera tra a e z, quindi restituirebbe cose come 123ae 456bma non restituirebbe un valore di 12ABC.

Voglio sapere se esiste un equivalente per la punteggiatura come [0-9]per i numeri e [a-z]per le lettere in modo che possa tornare AB!23e C?D789?

Se potessi usare un'espressione regolare, potrei usare l'espressione ^[a-zA-Z0-9]*$per abbinare caratteri alfanumerici in una stringa.

Where       Value like '^[a-zA-Z0-9]*$'

Esiste un equivalente SQL per questo?

Conosco questo tipo di cose che possono essere fatte in RegEx ma ne ho bisogno in T-SQL, non sono in grado di caricare alcun assembly personalizzato su questo server, quindi non posso usare espressioni regolari.

La colonna reale è varchar (200) . Le regole di confronto sono Latin1_General_CI_AS. Sto usando SQL Server 2012 Standard Edition.


Risposte:


12

La più grande difficoltà nel trovare una soluzione precisa è nel definire esattamente quali personaggi devono essere inclusi (o esclusi, qualunque direzione abbia più senso per l'operazione). Senso:

  • Stiamo parlando di VARCHAR/ dati ASCII o dati NVARCHAR/ Unicode? L'elenco dei caratteri di punteggiatura per i dati ASCII dipende dalla pagina del codice che a sua volta dipende dalla collazione. ( in questa domanda abbiamo a che fare con dati ASCII ).
  • Abbiamo a che fare con ricerche con distinzione tra maiuscole e minuscole o senza distinzione tra maiuscole e minuscole?
  • Su quale regole di confronto è impostata la colonna? La raccolta ci dirà sia la pagina di codice che la distinzione tra maiuscole e minuscole. ( in questa domanda abbiamo a che fareLatin1_General_CI_AS )
  • è il termine "punteggiatura" per indicare solo i caratteri di punteggiatura standard (ad esempio ., ,, ;, :, ecc) o lo fa caratteri medi non alfanumerici?
  • Sono inclusi i caratteri degli spazi bianchi?
  • I personaggi di controllo sono inclusi?
  • Che dire di simboli di valuta come ¢, £, ¥, ecc?
  • Che dire di simboli come ©e ?
  • Quali personaggi sono considerati "alfa"? Sono caratteri non inglesi, come Â, É, Ñ, ß, Þinclusi?
  • Poiché questa domanda riguarda le tastiere del Regno Unito (vedi la discussione per questa domanda), che dire del carattere Æ/ æ?

Al fine di facilitare la chiarezza sul comportamento previsto, la seguente query mostrerà tutti i 256 caratteri del set di caratteri Latin1 (ovvero Codice pagina 1252) e il funzionamento di due varianti della soluzione proposta da @ Shaneis . Il primo campo (etichettato come Latin1_General_CI_AS) mostra la LIKEclausola proposta da @Shaneis (al momento della stesura di questo documento) e il secondo campo (etichettato come Latin1_General_100_BIN2) mostra una modifica in cui ho scavalcato la Collation per specificarne una binaria (ovvero una Collation che termina in _BIN2; il _BINLe regole di confronto sono deprecate, quindi non utilizzarle se si ha accesso alle _BIN2versioni), il che significa che ho anche bisogno di aggiungere l' A-Zintervallo per filtrare le lettere maiuscole poiché l'attuale regole di confronto non fa distinzione tra maiuscole e minuscole:

;WITH nums AS
(
  SELECT TOP (256) (ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1) AS [Decimal]
  FROM   [master].[sys].[all_objects]
)
SELECT nm.[Decimal],
       CHAR(nm.[Decimal]) AS [Character],
       CASE WHEN CHAR(nm.[Decimal]) LIKE '%[^a-z0-9]%'
               THEN 'x' ELSE '' END AS [Latin1_General_CI_AS],
       CASE WHEN CHAR(nm.[Decimal]) LIKE '%[^a-z0-9A-Z]%' COLLATE Latin1_General_100_BIN2
               THEN 'x' ELSE '' END AS [Latin1_General_100_BIN2]
FROM   nums nm;

AGGIORNARE

Va detto che SE uno sta veramente cercando di trovare caratteri classificati come "punteggiatura" (e non "simbolo di valuta", "simbolo matematico", ecc.), E SE non è proibito usare SQLCLR / caricare un costume Assembly (SQLCLR è stato introdotto con SQL Server 2005 e non ho ancora trovato una buona ragione per non consentirlo, soprattutto perché il database SQL Azure V12 supporta gli SAFEassembly), quindi è possibile usare le espressioni regolari, ma non per il motivo che la maggior parte delle persone indovinerei.

Anziché utilizzare le espressioni regolari per creare un intervallo di caratteri più funzionale, o addirittura piuttosto che utilizzare qualcosa di simile \w(ovvero qualsiasi carattere di "parola"), è possibile specificare la categoria Unicode dei caratteri su cui si desidera filtrare e ci sono diverse categorie definite :

https://www.regular-expressions.info/unicode.html#category

Puoi anche specificare il blocco Unicode su cui filtrare, come "InBengali" o "InDingbats" o "InOptical_Character_Recognition", ecc.

https://www.regular-expressions.info/unicode.html#block

Esistono numerosi esempi di creazione di funzioni RegEx per SQL Server (sebbene la maggior parte degli esempi non segua le best practice SQLCLR), oppure è possibile scaricare la versione gratuita della libreria SQL # (che ho creato) e utilizzare la funzione scalEx RegEx_IsMatch come segue :

SQL#.RegEx_IsMatch(Unicode-String-Expression, N'\p{P}', 1, NULL)

L' \p{P}espressione significa \p= categoria Unicode e {P}= tutta la punteggiatura (al contrario di un tipo specifico di punteggiatura, come "Punteggiatura connettore"). E, la categoria "Punteggiatura" include tutta la punteggiatura in tutte le lingue! Puoi vedere l'elenco completo sul sito Unicode.org tramite il seguente link (al momento ci sono 717 punti di codice in quella categoria):

http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3AGeneral_Category%3DPunctuation%3A%5D

Una versione aggiornata della query di test mostrata sopra, incluso un altro campo che utilizza SQL # .RegEx_IsMatch con \p{P}, e i risultati di tutti e 3 i test su tutti i 256 caratteri di Code Page 1252 (cioè Latin1_General) è stata pubblicata su PasteBin.com all'indirizzo:

Query T-SQL e risultati per il filtraggio di tipi di caratteri


AGGIORNAMENTO
Nella discussione correlata è stato menzionato quanto segue:

Hai messo in evidenza i personaggi accentati, con i loro nomi di hotel da tutto il mondo ci saranno personaggi accentati nei nomi, per il mio problema vorrei classificarli come caratteri alfa validi.

In questo caso:

  1. Esistono 11 caratteri non inglesi inclusi nel set di caratteri Latino1 / Pagina di codice che non corrispondono a-zall'intervallo. Essi sono: ð Ð Þ þ œ Œ š Š ž Ž Ÿ. Questi devono essere aggiunti al carattere jolly e, sebbene al momento non sia necessario, non farebbe male aggiungere in A-Zmodo che il modello funzioni altrettanto bene su un confronto sensibile al maiuscolo / minuscolo. Il risultato finale è:
    LIKE '%[^a-zA-Z0-9ðÐÞþœŒšŠžŽŸ]%'

  2. Considerando che questi dati possono includere "nomi di hotel di tutto il mondo", consiglio vivamente di modificare il tipo di dati della colonna in NVARCHARmodo da poter memorizzare tutti i caratteri di tutte le lingue. Mantenere questo VARCHARrischio comporta un rischio molto elevato di avere alla fine la perdita di dati poiché è possibile rappresentare solo le lingue latine e nemmeno completamente per quelle date le sei categorie Unicode supplementari che forniscono caratteri aggiuntivi relativi al latino.


5

Potrei semplificare un po 'questo, ma, se diciamo che la punteggiatura è tutto ciò che rimane quando vengono rimossi i valori alfanumerici, allora quanto segue cercherà stringhe che contengono caratteri non alfanumerici.

Create Table #Test
(
Value   VarChar(10)
) 
Insert Into #Test
Values ('123a'), ('456b'), ('12ABC'),('AB!23'),('C?D789')

-- Original
Select      *
From        #Test
Where       Value like '[0-9][0-9][0-9][a-z]'

-- Non Alpha-numeric
SELECT * FROM #Test WHERE Value LIKE '%[^a-z0-9]%';

DROP TABLE #Test;
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.