首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 数据库 > SQL Server >

超疑窦 字符串解析

2013-08-06 
超疑难 字符串解析有这么一个字符串,if(4/(if(21,2,1)+2) 0,if(6/(3+3)1,3,2),4/(4+4)),怎么把他里面

超疑难 字符串解析
有这么一个字符串,if(4/(if(2>1,2,1)+2) = 0,if(6/(3+3)=1,3,2),4/(4+4))
,怎么把他里面的 和if左括号 匹配的 右小括号 都变成 右中括号。

处理前:if(4/(if(2>1,2,1)+2) = 0,if(6/(3+3)=1,3,2),4/(4+4))
处理后:if(4/(if(2>1,2,1]+2) = 0,if(6/(3+3)=1,3,2],4/(4+4)]

项目里很重要的一个功能,各位高手帮帮忙啊,谢了

sql?字符串处理?
[解决办法]
--仅供参考啊,汗~,期待好的算法……
--还是用程序实现比较方便。用CLR写个函数,放到SQL SERVER里来处理吧,最简单。

DROP TABLE #temp
CREATE TABLE #temp(id INT, expression VARCHAR(MAX))
INSERT #temp values(1, 'if(4/(if(2>1,2,1)+2) = 0,if(6/(3+3)=1,3,2),4/(4+4))')
--SQL
;WITH cte1 AS  
(
SELECT
id,
pos = CHARINDEX('(', expression),
word = CAST(LEFT(expression, CHARINDEX('(', expression) - 1) AS NVARCHAR(MAX)),
name = 1,
Split = CAST(STUFF(expression + '(', 1, CHARINDEX('(', expression + '('), '') AS NVARCHAR(MAX))
FROM #temp
UNION ALL
SELECT
id,
pos = a.pos + CHARINDEX('(', Split),
word = CAST(LEFT(Split, CHARINDEX('(', Split) - 1) AS NVARCHAR(MAX)),
name = 1,
Split = CAST(STUFF(Split, 1, CHARINDEX('(', Split), '') AS NVARCHAR(MAX))
FROM cte1 a
WHERE Split > ''
),
cte2 AS  
(
SELECT
id,
pos = CHARINDEX(')', expression),
word = CAST(LEFT(expression, CHARINDEX(')', expression) - 1) AS NVARCHAR(MAX)),
name = -1,
Split = CAST(STUFF(expression + ')', 1, CHARINDEX(')', expression + ')'), '') AS NVARCHAR(MAX))
FROM #temp
UNION ALL
SELECT
id,
pos = a.pos + CHARINDEX(')', Split),
word = CAST(LEFT(Split, CHARINDEX(')', Split) - 1) AS NVARCHAR(MAX)),
name = -1,
Split = CAST(STUFF(Split, 1, CHARINDEX(')', Split), '') AS NVARCHAR(MAX))


FROM cte2 a
WHERE Split > ''
),
cte3 AS
(
SELECT rowno = ROW_NUMBER() OVER(ORDER BY id, pos), * FROM
(
SELECT id,pos,word,name FROM cte1 WHERE pos < 52
UNION ALL
SELECT id,pos,word,name FROM cte2 WHERE pos < 52
) t 
),
cte4 AS
(
SELECT rowno, id,pos,word,name  FROM cte3 WHERE LEN(word) >= 2 AND UPPER(RIGHT(word, 2))='IF'
UNION ALL
SELECT b.rowno, b.id,a.pos,b.word,name=a.name+b.name
FROM cte4 a
INNER JOIN cte3 b
ON a.rowno = b.rowno-1
WHERE a.name+b.name > 0
)
SELECT RESULT=REPLACE(
(
SELECT A.WORD + (CASE WHEN a.name=1 THEN '(' WHEN A.NAME = -1 AND b.rowno IS NOT NULL THEN ']' ELSE ')' end)
FROM cte3 a
LEFT JOIN 
(
SELECT id, pos, rowno = MAX(rowno)+1
FROM cte4
group BY id, pos
) b
ON a.rowno = b.rowno
WHERE a.name = -1
ORDER BY a.id, a.pos
FOR XML PATH('')
),
'&gt;', '>'
)

/*
RESULT
if(4/(if(2>1,2,1]+2) = 0,if(6/(3+3)=1,3,2],4/(4+4)]
*/




[解决办法]

--第一步:创建自定义函数
create function [dbo].[test_if]
(@STR VARCHAR(MAX)) 
returns varchar(max)
as
begin

DECLARE @cu1 TABLE (SName varchar(1000),Number int,LR CHAR(1),re int ,number_R int,fz BIT)
DECLARE @cu2 TABLE (number_R int,re int)

INSERT @cu1
SELECT *,ROW_NUMBER() OVER(ORDER BY NUMBER) RE
,CAST(0 AS int) number_R
,CAST(0 AS BIT) fz
FROM
(
SELECT SName=SUBSTRING(a.SName,b.Number,Charindex('(',a.SName+'(',b.Number)-b.Number),
b.Number-1 Number,'L' LR
FROM (SELECT SName=@STR)a,master.dbo.spt_values b  
Where SUBSTRING('('+a.SName,b.Number,1)='(' and b.Type='P'
UNION ALL
SELECT SName=SUBSTRING(a.SName,b.Number,Charindex(')',a.SName+')',b.Number)-b.Number),
Charindex(')',a.SName+')',b.Number) Number,'R'
FROM (SELECT SName=@STR)a,master.dbo.spt_values b  
Where SUBSTRING(')'+a.SName,b.Number,1)=')' and b.Type='P'


) a

DECLARE @number_R int,@re_R int,@number_L int,@re_L int
WHILE EXISTS(SELECT 1 FROM @cu1 WHERE fz=0)
BEGIN
SELECT TOP 1 @number_R=number,@re_R=re FROM @cu1 WHERE lr='R' AND fz=0 ORDER BY re ASC
SELECT TOP 1 @number_L=number,@re_L=re FROM @cu1 WHERE lr='L' AND fz=0 AND re<@re_R ORDER BY re DESC
UPDATE @cu1 SET fz=1 WHERE re IN (@re_R,@re_L)
UPDATE @cu1 SET number_R=@number_R WHERE re=@re_L
END

;
WITH a1 AS
(
SELECT SName,number_R,ROW_NUMBER() OVER(ORDER BY re) re
FROM @cu1
WHERE lr='L'
)
INSERT @cu2
SELECT number_R,ROW_NUMBER() OVER(ORDER BY re) re
FROM a1 
WHERE re IN (SELECT re+1 re FROM a1 WHERE CHARINDEX('IF',UPPER(SName))>0)

DECLARE @i1 int,@i2 INT
SELECT @i1=1,@i2=MAX(re) FROM @cu2
WHILE @i1<=@i2
BEGIN
SELECT @number_R=number_R FROM @cu2 WHERE re=@i1
SET @STR=STUFF(@STR,@number_R,1,']')
SET @i1=@i1+1
END
return @STR
end

--第二步:执行自定义函数
SELECT dbo.test_if('if(4/(if(2>1,2,1)+2) = 0,if(6/(3+3)=1,3,2),4/(4+4))')

热点排行