Usando RegEx en SQL Server

92

Estoy buscando cómo reemplazar / codificar texto usando RegEx según la configuración / parámetros de RegEx a continuación:

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

He visto algunos ejemplos en RegEx, pero estoy confundido sobre cómo aplicarlo de la misma manera en SQL Server. Cualquier sugerencia sería útil. Gracias.

Dominante
fuente
1
Hola, eche un vistazo a este artículo: codeproject.com/Articles/42764/…
Mohsen
También hay una excelente solución TSQL + API de Windows en Robyn Page y Phil Factor's que se basa en la clase VBScript.RegExp , que, creo, se envía en todas las versiones de Windows desde Windows 2000.
Julio Nobre
Si es absolutamente necesario positivamente a través de expresiones regulares TSQL, una opción para SQL Server 2016 y arriba es para servicios de uso R .
Dave Mason

Respuestas:

103

No necesita interactuar con el código administrado, ya que puede usar 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

Cuando tu expresión termine con +, puedes ir con'%[^a-z0-9 .][^a-z0-9 .]%'

EDITAR : para aclarar: SQL Server no admite expresiones regulares sin código administrado. Dependiendo de la situación, el LIKEoperador puede ser una opción, pero carece de la flexibilidad que proporcionan las expresiones regulares.

Rubens Farias
fuente
8
@MikeYoung, tienes razón. Esta respuesta aborda incorrectamente el +cuantificador como {1,2}cuándo debería tomarlo como {1, }. Sorprendentemente, esto funcionó para el OP.
Rubens Farias
2
Esto no funciona en el servidor SQL ya que no es compatible con expresiones regulares.
VVN
10
@VVN, LIKEno es regex (es una sintaxis de coincidencia de patrones más limitada), por lo que la falta de compatibilidad con expresiones regulares no significa que esto no funcione.
Charles Duffy
@RubensFarias ¿no sería bueno actualizar la respuesta a la luz de los comentarios de @ mike-young?
Sudhanshu Mishra
8

Versión ligeramente modificada de la respuesta 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

Necesitará los procedimientos de automatización de Ole activados en 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
fuente
2
Por cierto, es mucho más rápido destruir y recrear el objeto regex que almacenarlo en caché y reutilizarlo. Hicimos 10,000 comparaciones con números significativamente más altos reutilizando el objeto.
Zachary Scott
8

Tendrá que crear un procedimiento CLR que proporcione la funcionalidad de expresiones regulares, como ilustra este artículo .

Su función de ejemplo usa 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

... y se instala en SQL Server usando el siguiente SQL (reemplazando '%' - variables delimitadas por sus equivalentes reales:

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
fuente
Esto es en ASP clásico, ¿es compatible? Creo que CLR es solo para funciones .NET, ¿verdad?
Control Freak
4
Los procedimientos CLR se instalan en el entorno de SQL Server y se pueden invocar como cualquier otro procedimiento almacenado o función definida por el usuario, por lo que si Classic ASP puede invocar un procedimiento almacenado o una función definida por el usuario, puede invocar un procedimiento CLR.
mwigdahl
1
Si bien este enlace puede responder la pregunta, es mejor incluir aquí las partes esenciales de la respuesta y proporcionar el enlace como referencia. Las respuestas de solo enlace pueden dejar de ser válidas si cambia la página enlazada. - De la crítica
Federico klez Culloca
Gracias @FedericoklezCulloca. Esta era una respuesta antigua y la actualicé en consecuencia.
mwigdahl
@mwigdahl gracias por eso. Veo que es viejo, pero apareció en una cola de revisión :)
Federico klez Culloca
7

Expresiones regulares en el uso de implementación de bases de datos de SQL Server

Expresión regular: descripción
. Coincidir con cualquier carácter
* Coincidir con cualquier carácter
+ Coincidir con al menos una instancia de la expresión antes
^ Comenzar al principio de la línea
$ Buscar al final de la línea
< Coincidir solo si la palabra comienza en este punto
> Coincidir solo si la palabra se detiene en este punto
\ n Coincidir con un salto de línea
[] Coincidir con cualquier carácter dentro de los corchetes
[^ ...] Coincide con cualquier carácter que no aparezca en la lista después de ^
[ABQ]% La cadena debe comenzar con las letras A, B o Q y puede tener cualquier longitud
[A B C D]% La cadena debe tener una longitud de dos o más y debe comenzar con A o B y tener C o D como segundo carácter
[AZ]% La cadena puede tener cualquier longitud y debe comenzar con cualquier letra de la A a la Z
[A -Z0-9]% La cadena puede tener cualquier longitud y debe comenzar con cualquier letra de la A a la Z o con un número del 0 al 9
[^ AC]% La cadena puede tener cualquier longitud pero no puede comenzar con las letras A a C
% [AZ] La cadena puede tener cualquier longitud y debe terminar con cualquiera de las letras de la A a la Z
% [% $ # @]% La cadena puede tener cualquier longitud y debe contener al menos uno de los caracteres especiales incluidos en el soporte

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

O alguna otra expresión en lugar de AZ

Kalyan Vasanth
fuente
1

Un enfoque similar a la respuesta de @ mwigdahl, también puede implementar un .NET CLR en C #, con código como;

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);
 }
}

Las instrucciones de instalación se pueden encontrar aquí

Fiach Reid
fuente