Utilisation de RegEx dans SQL Server

92

Je cherche comment remplacer / encoder du texte en utilisant RegEx en fonction des paramètres / paramètres RegEx ci-dessous:

RegEx.IgnoreCase = True     
RegEx.Global = True     
RegEx.Pattern = "[^a-z\d\s.]+"   

J'ai vu quelques exemples sur RegEx, mais je ne sais pas comment l'appliquer de la même manière dans SQL Server. Toute suggestion serait utile. Je vous remercie.

Control Freak
la source
1
Bonjour, jetez un œil à cet article: codeproject.com/Articles/42764/…
Mohsen
Il existe également une excellente solution d' API TSQL + Windows chez Robyn Page et Phil Factor qui repose sur la classe VBScript.RegExp , qui, je crois, est livrée sur toutes les versions de Windows depuis Windows 2000.
Julio Nobre
Si vous avez absolument besoin positivement RegEx via TSQL, une option pour SQL Server 2016 et ci - dessus est d' utiliser les services de R .
Dave Mason

Réponses:

103

Vous n'avez pas besoin d'interagir avec le code managé, car vous pouvez utiliser LIKE :

CREATE TABLE #Sample(Field varchar(50), Result varchar(50))
GO
INSERT INTO #Sample (Field, Result) VALUES ('ABC123 ', 'Do not match')
INSERT INTO #Sample (Field, Result) VALUES ('ABC123.', 'Do not match')
INSERT INTO #Sample (Field, Result) VALUES ('ABC123&', 'Match')
SELECT * FROM #Sample WHERE Field LIKE '%[^a-z0-9 .]%'
GO
DROP TABLE #Sample

Lorsque votre expression se termine, +vous pouvez aller avec'%[^a-z0-9 .][^a-z0-9 .]%'

EDIT : pour clarifier: SQL Server ne prend pas en charge les expressions régulières sans code managé. Selon la situation, l' LIKEopérateur peut être une option, mais il manque de la flexibilité que les expressions régulières offrent.

Rubens Farias
la source
8
@MikeYoung, vous avez raison. Cette réponse adresse incorrectement le +quantificateur comme {1,2}quand il devrait le prendre comme {1, }. Étonnamment, cela a fonctionné pour l'OP.
Rubens Farias
2
Cela ne fonctionnera pas dans le serveur sql car il ne prend pas en charge regex.
VVN
10
@VVN, LIKEn'est pas une expression régulière (c'est une syntaxe de correspondance de modèle plus limitée), donc l'absence de prise en charge de l'expression régulière ne signifie pas que cela ne fonctionnera pas.
Charles Duffy
@RubensFarias ne serait-il pas bien de mettre à jour la réponse à la lumière des commentaires de @ mike-young?
Sudhanshu Mishra
8

Version légèrement modifiée de la réponse de Julio.

-- MS SQL using VBScript Regex
-- select dbo.RegexReplace('aa bb cc','($1) ($2) ($3)','([^\s]*)\s*([^\s]*)\s*([^\s]*)')
-- $$ dollar sign, $1 - $9 back references, $& whole match

CREATE FUNCTION [dbo].[RegexReplace]
(   -- these match exactly the parameters of RegExp
    @searchstring varchar(4000),
    @replacestring varchar(4000),
    @pattern varchar(4000)
)
RETURNS varchar(4000)
AS
BEGIN
    declare @objRegexExp int, 
        @objErrorObj int,
        @strErrorMessage varchar(255),
        @res int,
        @result varchar(4000)

    if( @searchstring is null or len(ltrim(rtrim(@searchstring))) = 0) return null
    set @result=''
    exec @res=sp_OACreate 'VBScript.RegExp', @objRegexExp out
    if( @res <> 0) return '..VBScript did not initialize'
    exec @res=sp_OASetProperty @objRegexExp, 'Pattern', @pattern
    if( @res <> 0) return '..Pattern property set failed'
    exec @res=sp_OASetProperty @objRegexExp, 'IgnoreCase', 0
    if( @res <> 0) return '..IgnoreCase option failed'
    exec @res=sp_OAMethod @objRegexExp, 'Replace', @result OUT,
         @searchstring, @replacestring
    if( @res <> 0) return '..Bad search string'
    exec @res=sp_OADestroy @objRegexExp
    return @result
END

Vous aurez besoin des procédures d'automatisation Ole activées dans SQL:

exec sp_configure 'show advanced options',1; 
go
reconfigure; 
go
sp_configure 'Ole Automation Procedures', 1; 
go
reconfigure; 
go
sp_configure 'show advanced options',0; 
go
reconfigure;
go
Zachary Scott
la source
2
BTW, il est beaucoup plus rapide de détruire et de recréer l'objet regex que de le mettre en cache et de le réutiliser. Nous avons effectué 10 000 comparaisons avec des nombres significativement plus élevés de réutilisation de l'objet.
Zachary Scott
8

Vous devrez créer une procédure CLR qui fournit des fonctionnalités regex, comme l' illustre cet article .

Leur exemple de fonction utilise VB.NET:

Imports System
Imports System.Data.Sql
Imports Microsoft.SqlServer.Server
Imports System.Data.SqlTypes
Imports System.Runtime.InteropServices
Imports System.Text.RegularExpressions
Imports System.Collections 'the IEnumerable interface is here  


Namespace SimpleTalk.Phil.Factor
    Public Class RegularExpressionFunctions
        'RegExIsMatch function
        <SqlFunction(IsDeterministic:=True, IsPrecise:=True)> _
        Public Shared Function RegExIsMatch( _
                                            ByVal pattern As SqlString, _
                                            ByVal input As SqlString, _
                                            ByVal Options As SqlInt32) As SqlBoolean
            If (input.IsNull OrElse pattern.IsNull) Then
                Return SqlBoolean.False
            End If
            Dim RegExOption As New System.Text.RegularExpressions.RegExOptions
            RegExOption = Options
            Return RegEx.IsMatch(input.Value, pattern.Value, RegExOption)
        End Function
    End Class      ' 
End Namespace

... et est installé dans SQL Server à l'aide du SQL suivant (en remplaçant les variables délimitées par '%' par leurs équivalents réels:

sp_configure 'clr enabled', 1
RECONFIGURE WITH OVERRIDE

IF EXISTS ( SELECT   1
            FROM     sys.objects
            WHERE    object_id = OBJECT_ID(N'dbo.RegExIsMatch') ) 
   DROP FUNCTION dbo.RegExIsMatch
go

IF EXISTS ( SELECT   1
            FROM     sys.assemblies asms
            WHERE    asms.name = N'RegExFunction ' ) 
   DROP ASSEMBLY [RegExFunction]

CREATE ASSEMBLY RegExFunction 
           FROM '%FILE%'
GO

CREATE FUNCTION RegExIsMatch
   (
    @Pattern NVARCHAR(4000),
    @Input NVARCHAR(MAX),
    @Options int
   )
RETURNS BIT
AS EXTERNAL NAME 
   RegExFunction.[SimpleTalk.Phil.Factor.RegularExpressionFunctions].RegExIsMatch
GO

--a few tests
---Is this card a valid credit card?
SELECT dbo.RegExIsMatch ('^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\d{3})\d{11})$','4241825283987487',1)
--is there a number in this string
SELECT dbo.RegExIsMatch( '\d','there is 1 thing I hate',1)
--Verifies number Returns 1
DECLARE @pattern VARCHAR(255)
SELECT @pattern ='[a-zA-Z0-9]\d{2}[a-zA-Z0-9](-\d{3}){2}[A-Za-z0-9]'
SELECT  dbo.RegExIsMatch (@pattern, '1298-673-4192',1),
        dbo.RegExIsMatch (@pattern,'A08Z-931-468A',1),
        dbo.RegExIsMatch (@pattern,'[A90-123-129X',1),
        dbo.RegExIsMatch (@pattern,'12345-KKA-1230',1),
        dbo.RegExIsMatch (@pattern,'0919-2893-1256',1)
mwigdahl
la source
Ceci est dans ASP classique, prend-il en charge? Je pense que CLR est uniquement pour les fonctions .NET, non?
Control Freak
4
Les procédures CLR sont installées dans l'environnement SQL Server et peuvent être appelées comme toute autre procédure stockée ou fonction définie par l'utilisateur, donc si Classic ASP peut appeler une procédure stockée ou une fonction définie par l'utilisateur, il peut appeler une procédure CLR.
mwigdahl
1
Bien que ce lien puisse répondre à la question, il est préférable d'inclure les parties essentielles de la réponse ici et de fournir le lien pour référence. Les réponses aux liens uniquement peuvent devenir invalides si la page liée change. - De l'avis
Federico klez Culloca
Merci @FedericoklezCulloca. C'était une vieille réponse et je l'ai mise à jour en conséquence.
mwigdahl
@mwigdahl merci pour cela. Je vois qu'il est vieux, mais il est apparu dans une file d'attente de critiques :)
Federico klez Culloca
7

Utilisation d'expressions régulières dans l'implémentation de bases de données SQL Server

Expression régulière - Description
. Correspond à n'importe quel caractère
* Correspond à n'importe quel caractère
+ Correspond à au moins une instance de l'expression avant
^ Début au début de la ligne
$ Recherche à la fin de la ligne
< Correspondance uniquement si le mot commence à ce point
> Correspond uniquement si le mot s'arrête à ce point
\ n Correspond à un saut de ligne
[] Correspond à n'importe quel caractère entre crochets
[^ ...] Correspond à tout caractère non répertorié après ^
[ABQ]% La chaîne doit commencer par les lettres A, B ou Q et peut être de n'importe quelle longueur
[A B C D]% La chaîne doit avoir une longueur de deux ou plus et qui doit commencer par A ou B et avoir C ou D comme deuxième caractère
[AZ]% La chaîne peut être de n'importe quelle longueur et doit commencer par n'importe quelle lettre de A à Z
[A -Z0-9]% La chaîne peut être de n'importe quelle longueur et doit commencer par n'importe quelle lettre de A à Z ou par un chiffre de 0 à 9
[^ AC]% La chaîne peut être de n'importe quelle longueur mais ne peut pas commencer par les lettres A à C
% [AZ] La chaîne peut être de n'importe quelle longueur et doit se terminer par l'une des lettres de A à Z
% [% $ # @]% La chaîne peut être de n'importe quelle longueur et doit contenir au moins un des caractères spéciaux entre le support

Ravi Makwana
la source
5
SELECT * from SOME_TABLE where NAME like '%[^A-Z]%'

Ou une autre expression au lieu de AZ

Kalyan Vasanth
la source
1

Une approche similaire à la réponse de @ mwigdahl, vous pouvez également implémenter un CLR .NET en C #, avec un code tel que;

using System.Data.SqlTypes;
using RX = System.Text.RegularExpressions;

public partial class UserDefinedFunctions
{
 [Microsoft.SqlServer.Server.SqlFunction]
 public static SqlString Regex(string input, string regex)
 {
  var match = RX.Regex.Match(input, regex).Groups[1].Value;
  return new SqlString (match);
 }
}

Les instructions d'installation peuvent être trouvées ici

Fiach Reid
la source