Chinaunix
标题:
嵌套括号的递归匹配中,look-around assertions不生效
[打印本页]
作者:
routesf
时间:
2013-08-21 18:14
标题:
嵌套括号的递归匹配中,look-around assertions不生效
本帖最后由 routesf 于 2013-08-23 11:54 编辑
如下程序,括号{}的递归匹配被DATA中的引号中的一个}干扰,导致最终输出的结果少一个},我试图用(?<!\\)来屏蔽 “dfa-pattern "(ST\x00 01\xC|\x00\xX\x08 00\x\}\x08 0d 0a\x).*";”中的那个导致问题的\},但是不成功,有没有谁用过类似的东西
一个方案是用Text::Balanced,它可以忽略文中处于引号中的{},但是对格式要求比较严格,不如正则灵活,我想用正则来解决这个问题,但是一直没找到可行的方法
#!/usr/bin/perl5.12 -w
use strict;
my $ptn_no_keyword = qr/(
([\S]+)\s
(
\{
(
(?:
(?>[^{}]+)
|
(?3)
)*
)
\}
)
)/x;
local $/;
my $cfg = <DATA>;
if ($cfg =~ /$ptn_no_keyword/) {
print "$1\n";
} else {
print "Not matched\n";
}
__DATA__
application junos:PCANYWHERE {
type PCANYWHERE;
index 121;
port-mapping {
port-range {
tcp 5631;
udp 5632;
}
}
signature {
port-range {
tcp 0-65535;
udp 0-65535;
}
client-to-server {
dfa-pattern "(ST|\x00 00 00 00\x).*";
}
server-to-client {
dfa-pattern "(ST\x00 01\xC|\x00\xX\x08 00\x\}\x08 0d 0a\x).*";
}
min-data 8;
order 85;
}
}
复制代码
作者:
mcshell
时间:
2013-08-22 16:08
{:3_186:} 写的有点蛋疼 ,效果实现了,我在引号中多加了几个\{\}
回复
1#
routesf
#!/usr/bin/perl5.12 -w
use strict;
local $/;
my $cfg = <DATA>;
my @m = $cfg =~ /"[^"]+"/g; #取引号中的字符串
my $count;
for (@m) {
1 while (/\\}(?{$count++})/g);
1 while (/\\{(?{$count--})/g); #计算引号中的\{ 或\}个数
}
my $ptn_no_keyword = qr/((?{local $a=$count})(?>(?:([^{}]+)|
{(?{$a++})| #遇到开括号$a+1
}(?(?{$a!=0})(?{$a--})| #如果$a不等于0则遇到闭括号$a-1
(?!)))*)(?(?{$a!=0})(?!)))/x
; # 否则继续匹配,如果继续遇到$a不等于0 继续匹配到行尾
if ( $cfg =~ /$ptn_no_keyword/ ) {
print "$1\n";
}
else {
print "Not matched\n";
}
__DATA__
application junos:PCANYWHERE {
type PCANYWHERE;
index 121;
port-mapping {
port-range {
tcp 5631;
udp 5632;
}
}
signature {
port-range {
tcp 0-65535;
udp 0-65535;
}
client-to-server {
dfa-pattern "(ST|\x00 00 \}00 00\x).*";
}
server-to-client {
dfa-pattern "(ST\x00 01\xC|\x00\xX\x08\} \{00\x\}\x08 0d 0a\x).*";
}
min-data 8;
order 85;
}
}
复制代码
作者:
yinyuemi
时间:
2013-08-22 16:43
回复
1#
routesf
my $ptn_no_keyword = qr/(
([\S]+)\s
(
\{
(
(?:
(?>[^{}]+)
|
(?3)
|
(?>(\}|\{)) # adding another case
)*
)
\}
)
)/x;
复制代码
作者:
routesf
时间:
2013-08-23 11:51
感谢回复,我试了一下这个ptn,发现数据小的时候没问题,如果数据量比较大,则会出现out of memory,可见又加一个alternation对效率的影响非常大,附件是我用的文件,我的机器是CentOS4.5, 1G mem
回复
3#
yinyuemi
作者:
routesf
时间:
2013-08-23 11:55
传不了附件啊
回复
4#
routesf
作者:
routesf
时间:
2013-08-23 11:59
mcshell对regex的了解相当纯熟啊,先感谢,回头好好研究学习一下你的code
回复
2#
mcshell
作者:
yinyuemi
时间:
2013-08-23 12:06
回复
4#
routesf
数据量大的话,一般不推荐re,尤其当使用了回溯,用打点法比较保险和高效
作者:
routesf
时间:
2013-08-23 13:14
像mcshell这种算是打点法吗
回复
7#
yinyuemi
作者:
104359176
时间:
2013-08-23 14:51
看不懂需求,通常这种情况,可以先将捣乱的符号用另外一个符号替换掉,然后在做处理。处理完后,在恢复。
作者:
mcshell
时间:
2013-08-23 15:29
回复
8#
routesf
和堆栈的算法差不多。。。不过我也不懂什么算法
作者:
routesf
时间:
2013-08-23 16:54
需求是这样的:
1. 有如下文本文件,内容有2种情况,一种是xxx {...多层嵌套{},层数未知},另一种是没有{}的类似 version 10.4;
fxp0 {
unit 0 {
family inet {
address 10.208.85.48/21 {
master-only;
}
}
}
}
apply-groups [ re0 re1 global "${node}" ];
version 10.4;
lo0 {
unit 0 {
family inet {
address 74.11.0.1/32;
}
}
}
2. 我想用一个正则来匹配所有 xxx {...}, 通过@array = $cfg =~ /$ptn/g把它存到一个数组里,如下正则大部分情况下是没问题的,但处理不了下面这种情况,也就是引号里边出现未匹配的{},但是引号里出现未匹配的{}是允许的
server-to-client {
dfa-pattern "(ST\x00 01\xC|\x00\xX\x08 00\x\}\x08 0d 0a\x).*";
}
my $ptn = qr/(
([\S]+)\s
(
\{
(
(?:
(?>[^{}]+)
|
(?3)
)*
)
\}
)
)/x;
回复
9#
104359176
作者:
yinyuemi
时间:
2013-08-23 17:13
回复
8#
routesf
我觉得是的,下面是我写的,思路基本是一样的,供你参考吧
#!/usr/bin/perl5.12 -w
use strict;
my $tag;
my $text;
while(<DATA>){
if(/(?<!\\)[{]/){
$tag = 1;
$text = $_;
while(<DATA>){
$tag += /(?<!\\)[{]/ ? 1 :
/(?<!\\)[}]/ ? -1 : 0;
$text .= $_;
last if ! $tag;
}
print $text;
}
}
__DATA__
xxx
application junos:PCANYWHERE {
type PCANYWHERE;
index 121;
port-mapping {
port-range {
tcp 5631;
udp 5632;
}
}
signature {
port-range {
tcp 0-65535;
udp 0-65535;
}
client-to-server {
dfa-pattern "(ST|\x00 00 00 00\x).*";
}
server-to-client {
dfa-pattern "(ST\x00 01\xC|\x00\{\xX\x08 00\x\}\x08 0d 0a\x).*";
}
min-data 8;
order 85;
}
}
XXX
xxx
application junos:PCANYWHERE {
type PCANYWHERE;
index 121;
port-mapping {
port-range {
tcp 5631;
udp 5632;
}
}
signature {
port-range {
tcp 0-65535;
udp 0-65535;
}
client-to-server {
dfa-pattern "(ST|\x00 00 00 00\x).*";
}
server-to-client {
dfa-pattern "(ST\x00 01\xC|\x00\{\xX\x08 00\x\}\x08 0d 0a\x).*";
}
min-data 8;
order 85;
}
}
XXX
复制代码
作者:
104359176
时间:
2013-08-23 18:16
你需要用一个算法把所有的字符串,也就是 "" 之间的东西替换掉,把替换结果保存到一个别的数据结构中。
剩下的事情就简单了多了。
code "string1" code "string2"
=> code <s1> code <s2>
{
s1 => 'string1',
s2 => 'string2',
}
提取完了,然后在替换回来。
作者:
pitonas
时间:
2013-08-23 18:17
yinyuemi 发表于 2013-08-23 05:06
回复 4# routesf
用打点法比较保险和高效
复制代码
thanks~ what is 打点法? please give me an example about taht ..
作者:
routesf
时间:
2013-08-23 18:23
不错的思路,找空尝试一下
回复
13#
104359176
作者:
routesf
时间:
2013-08-23 18:27
我理解yinyuemi的打点法是用一个statck,遇到左括号就push,右括号就pop,类似这样的
回复
14#
pitonas
作者:
pitonas
时间:
2013-08-23 18:38
回复
16#
routesf
thanks !
please give me an example about taht...please~~
作者:
yinyuemi
时间:
2013-08-23 19:27
回复
14#
pitonas
#!/usr/bin/env perl
use strict;
my $dots;
my $ext;
while(<DATA>){
if(/{/){
$dots =~ s/^/./;
p($_);
$ext .= $_;
while(<DATA>){
/{/ ? do {$dots =~ s/^/./} :
/}/ ? do {$dots =~ s/\.//} : do {$dots .= ""};
p($_);
$ext .= $_;
last if $dots !~ /\./;
}
}else{
p($_)
}
}
print "\nExtract: \n",$ext,"\n";
sub p(){
print "Dot: $dots\t\t",shift;
}
__DATA__
###
xxx{
yyy{
zzz{
###
}
}
}
###
复制代码
作者:
yakczh_cu
时间:
2013-08-24 11:09
本帖最后由 yakczh_cu 于 2013-08-24 11:09 编辑
/{/ ? do {$dots =~ s/^/./} : /}/ ? do {$dots =~ s/\.//} : do {$dots .= ""};
复制代码
这是三目运算吗?
作者:
pitonas
时间:
2013-08-24 17:17
回复
18#
yinyuemi
thank you very much!!
作者:
yakczh_cu
时间:
2013-08-26 19:25
###
vvv{
xxx{
yyy{
zzz{
###
}
}
}
###
复制代码
象这种也匹配出来了,明显不匹配
作者:
routesf
时间:
2013-08-26 21:56
你用的哪个正则?
回复
21#
yakczh_cu
作者:
yakczh_cu
时间:
2013-08-26 22:43
回复
22#
routesf
use strict;
my $depth;
my $last;
my $ext="------";
open FH,q(c:\nginx\conf\nginx.conf);
while(<FH>){
$last=$depth;
$depth++ if /{/;
$depth-- if /}/;
$ext .= $_;
if( $depth==0 && $depth < $last ){
$ext.="------";
}
}
if($depth ==0 ){
print "\nExtract: \n",$ext,"\n";
}else {
print "\nnot match";
}
复制代码
改了一个,可以用这个来匹配nginx配置文件
欢迎光临 Chinaunix (http://bbs.chinaunix.net/)
Powered by Discuz! X3.2