帮忙看看这个正则表达式有什么问题!

allanli 2010-06-09 11:40:43
正则表达式为:\((?:(?<l>\()?[^()]*(?<r-l>\))?)+\)


如果能简单说明一下这个表达式的和死掉的原因就最好了
本人对正则表达式一知半解,呵呵,这个表达式高人帮忙写的,今天遇到匹配这个字符串就死掉了.
当匹配以下内容时就会出现假死现象(死掉不动了)

select AS_Ware.WareName
,max(RZ_ProductOrder.ProductOrderid) as ProductOrderid
into #abc
from RZ_ProductOrder left join as_ware on AS_Ware.WareID = RZ_ProductOrder.ProductWareID
where RZ_ProductOrder.FunctionID=173
group by AS_Ware.WareName


select * into #123 from
(
select
AS_Ware.WareName
,RZ_ProductOrder.ProductOrderid
,reverse(substring(reverse(rtrim(AS_Ware.WareName)),2,case when patindex('%(%',reverse(rtrim(AS_Ware.WareName)))>0 then
patindex('%(%',reverse(rtrim(AS_Ware.WareName)))-2 else 0 end)) as 纸板代号
,reverse(right(reverse(rtrim(AS_Ware.WareName)),len(rtrim(AS_Ware.WareName))-patindex('%(%',reverse(rtrim(AS_Ware.WareName)))))
as 名称
,AS_Ware.WareCode as 产品编号
,RZ_ProductOrder.ProductOrderFree10 as 材料名称
,cast(left(RZ_ProductOrder.ProductOrderFree11,patindex('%X%',RZ_ProductOrder.ProductOrderFree11)-1) as decimal(18,1)) as 规格1
,cast(right(RZ_ProductOrder.ProductOrderFree11,len(RZ_ProductOrder.ProductOrderFree11)-patindex('%X%',RZ_ProductOrder.ProductOrderFree11)) as decimal(18,1)) as 规格2
,cast(case when RZ_ProductOrder.ProductOrderFree10 like '%牛%' then 0 else substring(RZ_ProductOrder.ProductOrderFree10,1,3) end as decimal(18,0)) as 规格3
,RZ_ProductOrder.ProductOrderFree6 as 白板纸规格
,RZ_ProductOrder.ProductOrderFree44 as 印刷面积
,RZ_ProductOrder.ProductOrderFree50 as 成品面积
,case when RZ_ProductOrder.ProductOrderFree27='是' then '过油' else '无' end as 彩纸表面处理
,'啤箱:'+cast(RZ_ProductOrder.ProductOrderFree65 as varchar(50)) as 成型工序类型
,'裱纸:'+cast(RZ_ProductOrder.ProductOrderFree34 as varchar(50)) as 裱纸工序类型
,'钉箱:'+cast(RZ_ProductOrder.ProductOrderFree66 as varchar(50)) as 钉箱类型
--,RZ_ProductOrder.ProductOrderFree15

from RZ_ProductOrder left join as_ware on AS_Ware.WareID = RZ_ProductOrder.ProductWareID
where RZ_ProductOrder.FunctionID=173 --and RZ_ProductOrder.ProductOrderFree10 is not null

union all

select AS_Ware.WareName
,RZ_ProductOrder.ProductOrderid
,reverse(substring(reverse(rtrim(AS_Ware.WareName)),2,case when patindex('%(%',reverse(rtrim(AS_Ware.WareName)))>0 then
patindex('%(%',reverse(rtrim(AS_Ware.WareName)))-2 else 0 end)) as 纸板代号
,reverse(right(reverse(rtrim(AS_Ware.WareName)),len(rtrim(AS_Ware.WareName))-patindex('%(%',reverse(rtrim(AS_Ware.WareName)))))
as 名称
,AS_Ware.WareCode as 产品编号
,RZ_ProductOrderlist.ProductOrderListMemo as 材料名称
,cast(left(RZ_ProductOrder.ProductOrderFree11,patindex('%X%',RZ_ProductOrder.ProductOrderFree11)-1) as decimal(18,1)) as 规格1
,cast(right(RZ_ProductOrder.ProductOrderFree11,len(RZ_ProductOrder.ProductOrderFree11)-patindex('%X%',RZ_ProductOrder.ProductOrderFree11)) as decimal(18,1)) as 规格2
,cast(RZ_ProductOrderlist.StandardNumber as decimal(18,0)) as 规格3
,RZ_ProductOrder.ProductOrderFree6 as 白板纸规格
,RZ_ProductOrder.ProductOrderFree44 as 印刷面积
,RZ_ProductOrder.ProductOrderFree50 as 成品面积
,case when RZ_ProductOrder.ProductOrderFree27='是' then '过油' else '无' end as 彩纸表面处理
,case when RZ_ProductOrderlist.ProductOrderListMemo like '%瓦%' then '撕纸:'+cast(RZ_ProductOrder.ProductOrderFree46 as varchar(50)) else '' end as 成型工序类型
,cast(null as varchar(50)) as 裱纸工序类型
,cast(null as varchar(50)) as 钉箱类型
--,RZ_ProductOrder.ProductOrderFree15

from RZ_ProductOrder left join RZ_ProductOrderlist on

RZ_ProductOrder.ProductOrderid=RZ_ProductOrderlist.ProductOrderid
left join as_ware on AS_Ware.WareID = RZ_ProductOrder.ProductWareID
where RZ_ProductOrder.FunctionID=173 and RZ_ProductOrderlist.ProductOrderListMemo is not null

) as aa



select #123.*,round(#123.规格1*#123.规格1*#123.规格1/10000000,4) as 单耗
into #tempaa
from #123 inner join #abc on #123.warename=#abc.warename and #123.ProductOrderid=#abc.ProductOrderid order by #123.产品编号,#123.规格3 desc




select * from #tempaa

drop table #abc,#123,#tempaa
...全文
222 38 打赏 收藏 转发到动态 举报
写回复
用AI写文章
38 条回复
切换为时间正序
请发表友善的回复…
发表回复
-过客- 2010-06-10
  • 打赏
  • 举报
回复
[Quote=引用 37 楼 allanli 的回复:]
啊!如果真的这么难的话看来只能自己写函数了
因为我这个表达式是用来处理SQL语句的,你知道SQL语句什么写法的都有,更复杂更变态的都有
但回过头想一下应该有办法处理吧,SQL Server的语法分析器就能轻松判断语法问题啊[/Quote]

SQL语法分析器必然不是使用正则进行的解析
正则非常适合于那种轻量级的,灵活多变的需求,但并不适合重量级的,如百万组数据量或逻辑非常复杂的需求,不是不能做,是不适合做

正则不是为某一特定需求定制的,所以在实现特定需求时,必然会带来一定程度的性能损失
其实正则也不过是有穷自动机的一种实现,针对特定需求,完全可以自己去实现有穷自动机,以提升性能
allanli 2010-06-10
  • 打赏
  • 举报
回复
[Quote=引用 36 楼 lxcnn 的回复:]

引用 35 楼 allanli 的回复:
这个需求其实应该很多地方有用吧,例如我上面讲到的表达式计算的问题
一般函数都是 函数名(参数),如果我需要提取这个函数出来就需要这个表达式了
因为参数里面很可能是有函数嵌套的,括号嵌套更加是不可避免了
还是期待有更简单的表达式,这么复杂的一个表达式去实现这么一个简单的需求觉得挺别扭的


需求简单吗?
需求或许并不复杂,那我只能说你要处理……
[/Quote]

啊!如果真的这么难的话看来只能自己写函数了
因为我这个表达式是用来处理SQL语句的,你知道SQL语句什么写法的都有,更复杂更变态的都有
但回过头想一下应该有办法处理吧,SQL Server的语法分析器就能轻松判断语法问题啊
-过客- 2010-06-10
  • 打赏
  • 举报
回复
[Quote=引用 35 楼 allanli 的回复:]
这个需求其实应该很多地方有用吧,例如我上面讲到的表达式计算的问题
一般函数都是 函数名(参数),如果我需要提取这个函数出来就需要这个表达式了
因为参数里面很可能是有函数嵌套的,括号嵌套更加是不可避免了
还是期待有更简单的表达式,这么复杂的一个表达式去实现这么一个简单的需求觉得挺别扭的
[/Quote]

需求简单吗?
需求或许并不复杂,那我只能说你要处理的数据太变态了
严格说27楼的正则不满足需求,而我33楼写的正则也只能满足你的个例,比如%(%变成%sum(%就不能用了,如果要通用,必然要提高复杂度

带嵌套的需求,用正则来处理就必然要用到平衡组,这没什么好说的
如果你认为33楼的正则太复杂,或是效率达不到你的要求,那我只能说,正则不适合你的需求,要提升效率,自己写算法实现吧
allanli 2010-06-10
  • 打赏
  • 举报
回复
这个需求其实应该很多地方有用吧,例如我上面讲到的表达式计算的问题
一般函数都是 函数名(参数),如果我需要提取这个函数出来就需要这个表达式了
因为参数里面很可能是有函数嵌套的,括号嵌套更加是不可避免了
还是期待有更简单的表达式,这么复杂的一个表达式去实现这么一个简单的需求觉得挺别扭的
APP开发王 2010-06-10
  • 打赏
  • 举报
回复

友情帮顶下!顺便学习学习!
-过客- 2010-06-10
  • 打赏
  • 举报
回复
这样效率应该会再提升一些
Regex reg = new Regex(@"(?n)\((?>(%[()]%|[^()])|\((?<o>)|\)(?<-o>))*(?(o)(?!))\)");
MatchCollection mc = reg.Matches(yourStr);
foreach (Match m in mc)
{
richTextBox2.Text += m.Value + "\n-------------------------\n";
}


至于下面这样是否能再提升效率,就与你的源字符串相关了
Regex reg = new Regex(@"(?n)\((?>(%[()]%|[^()])|\((?<o>)|\)(?<-o>))*(?(o)(?!))\)", RegexOptions.Compiled);


另外27楼正则在你原有例子基础上再拼接一遍时,获取的结果是错的
现在没时间,没有办法测试匹配效率,楼主自己测下吧
allanli 2010-06-10
  • 打赏
  • 举报
回复
[Quote=引用 29 楼 lxcnn 的回复:]

需求或许没什么,但例子不可谓不变态

C# code
Regex reg = new Regex(@"(?n)\((([^()]|%[()]%)|\((?<o>)|\)(?<-o>))*(?(o)(?!))\)");
MatchCollection mc = reg.Matches(yourStr);
foreach (Match m in mc)
{
richTextBox2.T……
[/Quote]

这个效率比27楼的高很多了,不会感觉到延时
再等等看看有没有更快的,有没有不用什么平行组的啊,呵呵
兔子-顾问 2010-06-09
  • 打赏
  • 举报
回复
平衡组……心中的痛

师傅来了。
兔子-顾问 2010-06-09
  • 打赏
  • 举报
回复
\((?>(?<l>\()?[^()]*(?<r-l>\))?)+\)
兔子-顾问 2010-06-09
  • 打赏
  • 举报
回复
对于你这个特定的测试文本。因为表达式第一个要匹配文本 ( 。所以第一次的匹配就是

select AS_Ware.WareName
,max(
的最后一个字符,理论上,最后这个(也就是结果的开始。
而最后导致你正则引擎崩溃的原因恰是最后的一段

) as 单耗
into #tempaa
from #123 inner join #abc on #123.warename=#abc.warename and #123.ProductOrderid=#abc.ProductOrderid order by #123.产品编号,#123.规格3 desc




select * from #tempaa

drop table #abc,#123,#tempaa

因为正则表达式是左向右的方向匹配的。而你恰好有用了大量的贪婪模式匹配,((?:(?<l>\()?[^()]*(?<r-l>\))?)+这个表达式其实很容易失败的,但是当失败后,又会尝试的找下一个(符号进行匹配,希望表达式尽可能成立,当所有可能都失败之后,发现匹配到文本末端了。才会导致整个表达式的失败。快速的使表达式失败,可以用原子组 (?>) 你这个表达式修改后,可以这样用

\((?[color=#FF0000]>[/color](?<l>\()?[^()]*(?<r-l>\))?)+\)
-过客- 2010-06-09
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 wuyazhe 的回复:]
用了太多的非贪婪匹配,导致了无限回溯,正则引擎内部有一个超大循环,有生之年等不到退出了。
[/Quote]

不是非贪婪模式的问题,那个正则用的全是贪婪模式,没有非贪婪模式

是量词嵌套导致的无限循环

楼主要实现什么功能?配对出现的()?参考
.NET正则基础之——平衡组
3.1节讨论的就是
兔子-顾问 2010-06-09
  • 打赏
  • 举报
回复
死掉的原因说错了。你没有用非贪婪匹配,但是这些贪婪匹配的任何一项都可以回溯,规则太灵活了。分析如下

\(               	文本(
(?: 非捕获组,整体捕获但不创建堆栈存储分组结果
( 分组匹配,将数据分组压入堆栈
?<l> 这是分组名
\( 文本(
)? 贪婪匹配,0次或1次,尽可能的匹配,所以会先尝试存在的情况,如果不存在,则回溯
[^()]* 非()的任意字符,贪婪匹配,0次或多次,尽可能多的匹配,但如果后续表达式不成立,则回溯
(?<r-l>\))? 分组匹配,命名为r-l匹配文本),贪婪匹配。
)+ 贪婪匹配,尽可能多的匹配分组结果
\)
捷哥1999 2010-06-09
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 wuyazhe 的回复:]

用了太多的非贪婪匹配,导致了无限回溯,正则引擎内部有一个超大循环,有生之年等不到退出了。
[/Quote]

顶!
兔子-顾问 2010-06-09
  • 打赏
  • 举报
回复
如果不考虑嵌套。这样试试看是否符合你要求。
(?<b>\()([^()]+)(?<-b>\))(?(b)(?!))
兔子-顾问 2010-06-09
  • 打赏
  • 举报
回复
用了太多的非贪婪匹配,导致了无限回溯,正则引擎内部有一个超大循环,有生之年等不到退出了。
jiongjiongtang 2010-06-09
  • 打赏
  • 举报
回复
不会,帮顶。。。。。
小黑哥gs 2010-06-09
  • 打赏
  • 举报
回复
跟长篇小说一样。。
兔子-顾问 2010-06-09
  • 打赏
  • 举报
回复
%是干嘛的?
-过客- 2010-06-09
  • 打赏
  • 举报
回复
需求或许没什么,但例子不可谓不变态

Regex reg = new Regex(@"(?n)\((([^()]|%[()]%)|\((?<o>)|\)(?<-o>))*(?(o)(?!))\)");
MatchCollection mc = reg.Matches(yourStr);
foreach (Match m in mc)
{
richTextBox2.Text += m.Value + "\n-------------------------\n";
}
allanli 2010-06-09
  • 打赏
  • 举报
回复
[Quote=引用 27 楼 wackyboy 的回复:]

C# code

//平衡组
@"\([^()]*((?<g>\([^()]*)+(?<-g>\)[^()]*)+[^()]*)*\)"
[/Quote]

终于有一个成功匹配我例子的了,呵呵
不过这个表达式明显感觉到延时,效率有待提高,比起SQL Server的语法分析差远了
等待更好的,其实大家可不可以换个角度考虑
不要被我第一个表达式先入为主了呢,其实我的要求不复杂嘛,
就是要求匹配所有()里面的内容,只不过增加一个嵌套的就要取最外层的()而已
这个其实在编译程序的时候很多时候都需要考虑的,最简单的就是表达式就是很多括号的
一般都是需要提取()里面的内容吧,这个时候就要考虑()的嵌套啦
加载更多回复(18)

110,532

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧