Имитация регулярных выражений на SQL2008. Помогите превратить говнокод в пирожное.

_Промешан_
Дата: 06.02.2013 15:01:30
В общем в спойлере некий говнокод за 10 минут, которые выполняет имитацию регулярок, при этом большего не требуется от него, однако хочется сделать красиво, по возможности без циклов.
И заодно спросить, не слишком ли OLE-шные приблуды грузятся долго, если делать CLR?

+
ALTER FUNCTION [dbo].[ReplaceByRegEx_f](@text varchar(2048),@RegEx varchar(200)) 
RETURNS varchar(2048)
AS
BEGIN
	/*
		Regext pattern: expr1=repl1|expr2=repl2|
		Example: 'asdg109,6d' need 109.6 => RegEx: asdg=|d=|,=.|  //  | - разделитель.  = - знак равенства
		--select dbo.ReplaceByRegEx('asdg100,6d','asdg=|d=|,=.|')
	*/
	if right(@RegEx,1) != '|' 
	  set @RegEx = @RegEx + '|'

	declare @v varchar(50),@e1 smallint,@e2 smallint, @r1 smallint,@r2 smallint, @one varchar (100)='', @next smallint


	while LEN(@RegEx) > 0 
	begin
		set @next = CHARINDEX('|',@RegEx)
		set @one = Substring(@RegEx,1,@next)
		set @e1 = 1
		set @e2 = charindex('=',@one)-1
		set @r1 = charindex('=',@one)+1
		set @r2 = charindex('|',@one)-1
		if @r2 < @r1
			set @text = replace(@text,substring(@one,@e1,@e2),'')
		else	
			set @text = replace(@text,substring(@one,@e1,@e2),substring(@one,@r1,@r2-@r1+1))
		set @RegEx = RIGHT(@RegEx,Len(@RegEx)-@next)
	end

	
	RETURN @text

END
Ken@t
Дата: 06.02.2013 15:21:07
_Промешан_,

RegExp можно CLR сделать, если допустимо равернуть на продуктиве.
Но наша практика показала, что нет необходимости в этом, как и sp_OA... и xp_cmdshell ... Все задачи использующие это - легко преобразуются в приложения или рабочие роли.
_Промешан_
Дата: 06.02.2013 15:24:57
Ken@t
_Промешан_,

RegExp можно CLR сделать, если допустимо равернуть на продуктиве.
Но наша практика показала, что нет необходимости в этом, как и sp_OA... и xp_cmdshell ... Все задачи использующие это - легко преобразуются в приложения или рабочие роли.
Можете по-подробнее?

И как то за одно в контексте "из говнокода - пирожок"?

Ну может быть хотя бы данный код "причесать".
Ken@t
Дата: 06.02.2013 15:46:18
ч0 уж там, можно...
Вот например
_Промешан_
Дата: 06.02.2013 16:14:26
Ken@t
ч0 уж там, можно...
Вот например
А если без CLR?

OLE же вообще не быстрая весчь.
Ken@t
Дата: 06.02.2013 16:17:17
_Промешан_
Ken@t
ч0 уж там, можно...
Вот например
А если без CLR?

OLE же вообще не быстрая весчь.

OLE и CLR - это мягкое и тёплое.
_Промешан_
Дата: 06.02.2013 17:04:18
Ken@t
_Промешан_
пропущено...
А если без CLR?

OLE же вообще не быстрая весчь.

OLE и CLR - это мягкое и тёплое.
Ой да, точно.
dalex1973
Дата: 06.02.2013 17:18:20
Ken@t,
Пирожка не получится, но если Вы фанат TSQL, то как вариант:
Разделяете @Regex и вставляете в таблицу с помощью функции ufnsplit. Примеров масса , например тут
Когда данные разделены, замену делаете рекурсивным CTE.

+
DECLARE @Pattern NVARCHAR (MAX) = 'asdg=|d=|,=.|';



DECLARE @Table TABLE (Id TINYINT IDENTITY(1, 1) PRIMARY KEY,Value NVARCHAR(4000));

INSERT INTO @Table (Value)
VALUES ('asdg109,6d'),('NoChange'),('dasdg,,,d')

DECLARE @Patterns TABLE (Id TINYINT IDENTITY(1, 1) PRIMARY KEY,Source NVARCHAR(255),Dest NVARCHAR(255))


INSERT INTO @Patterns (Source,Dest)
select (select T2.Data from [dbo].ufnSplit(T1.Data,'=') T2 WHERE T2.Id=1),
(select T2.Data from [dbo].ufnSplit(T1.Data,'=') T2 WHERE T2.Id=2)
 from [dbo].ufnSplit(@Pattern,'|') T1
 WHERE T1.Data!=''


;WITH H (Id,Value,Lvl)
AS (
	SELECT T.Id
		,REPLACE(T.Value, P.Source, P.Dest)
		,CAST(1 AS TINYINT)
	FROM @Table T
	CROSS JOIN @Patterns P
	WHERE P.Id = 1
	
	UNION ALL
	
	SELECT H.Id
		,REPLACE(H.Value, P.Source, P.Dest)
		,CAST(Lvl + 1 AS TINYINT)
	FROM H
	INNER JOIN @Patterns P ON P.Id = H.Lvl + 1
	)
SELECT *
FROM [H]
WHERE H.Lvl = (
		SELECT MAX(H2.lvl)
		FROM [H] H2
		WHERE H.Id = H2.Id
		)
ORDER BY [H].Id
_Промешан_
Дата: 06.02.2013 17:44:06
dalex1973,

Хм. Любопытно.
А по плану, что быстрее работает, рекурсивный вариант или цикличный?
aleks2
Дата: 07.02.2013 06:30:57
_Промешан_
dalex1973,

Хм. Любопытно.
А по плану, что быстрее работает, рекурсивный вариант или цикличный?

Быстрее всего - табличный. Ибо избавляет аж от двух операций: соединение строки и разбор строки.