我有string
Message <Network=Data Center> All Verified
我需要提取除括号之外的所有string
我试过了
m/(?![^<]*\\>)/s
没有给出预期的结果。
<..>
区域 从字符串中删除<..>
部分,然后处理剩下的字符串更容易。
试试这个oneliner:
cat file | perl -pne 's/<[^>]*?>//g;'
对于您的示例输入,这是输出:
Message All Verified
注意非贪婪的量词 ?
在正则表达式中使用。 另外,因为这是一个oneliner,所以s///
search-and-replace结构被应用于$_
隐式变量(这是一个来自标准输入的行)。 所以在搜索和替换运行后, $_
将被改变(将不会有<..>
区域)。 另外,为了在运行代码块之后打印变量$_
,还使用了-p
。 您可以在perlrun中阅读关于Perl命令行开关的更多信息。
这是一个解决方案。 下面还有一个:
<..>
之外的区域 另一方面,你可以(如果你想)匹配<..>
区域以外的部分。
为了做到这一点,让我们建立一个正则表达式。 首先,我们要一个<
或>
自由区域。 下面的正则表达式匹配
$p = ([^<>]*)
。
接下来,我们希望在<
之前匹配所有内容,为此我们可以编写(?:$p<)
和>
之后的所有内容,即(?:>$p)
。
现在,如果我们将所有这些部分组合在一起,我们得到(?:>$p)|(?:$p<)
。
注意(?:)
是一个非捕获组。
所以现在有两个捕获组(两个$p
你看到上面),但只有一个将匹配一次,所以一些捕获将是undef
。 我们将不得不将这些过滤掉。
最后,我们可以组装所有的捕获,我们就完成了。
cat file | perl -ne '$p="([^<>]*)";@x=grep{defined} m{(?:>$p)|(?:$p<)}g; print join(" ",@x)."\n";'
Parse::Yapp
解析器 你可能会认为使用Parser::Yapp
这个特定的问题有点太多了(通常,如果你有一些复杂的解析,你会使用语法和解析器生成器 ),但..为什么不.. .. 🙂
好的,我们需要一个语法,这里是一个grammar_file.yp
:
#header %% #rules expression: | exterior '<' interior '>' exterior | exterior ; exterior: | TOK { $_[0]->YYData->{DATA} .= $_[1]; } | expression ; interior: TOK; %% #footer sub Error { my ($parser)=shift; } sub Lexer { use Data::Dumper; my($parser)=shift; $parser->YYData->{INPUT} or return('',undef); #$parser->YYData->{INPUT}=~s/^\s+//; for ($parser->YYData->{INPUT}) { return ('TOK',$1) if(s/^([^<>]+)//); return ( $1,$1) if(s/^([<>])//); }; }
你会注意到在上面的语法interior
完全忽略了interior
,只有exterior
的终端被收集。
这是一个小程序,它将使用解析器(从grammar_file.yp
生成的grammar_file.yp
) parse.pl
:
#!/usr/bin/env perl use strict; use warnings; use MyParser; my $parser=MyParser->new; $parser->YYData->{INPUT} = "Message <Network=Data Center> All Verified"; my $value=$parser->YYParse( yylex => \&MyParser::Lexer, yyerror => \&MyParser::Error, #yydebug => 0x1F, ); my $nberr=$parser->YYNberr(); my $data=$parser->YYData->{DATA}; print "Result=$data"
现在一个Makefile
,我们完成了:
generate_parser_module: yapp -m MyParser grammar_file.yp; run: perl parse.pl all: generate_parser_module
更多的分析器发生器可以在这里找到
你可以用其他方法来做:只要在尖括号中删除字符串:
s@<.*>@@
或者如果不允许:
s@<[^>]*>@@
你可以使用sed
:
cat yourfile |sed 's/<.*>//g' > newfile
如果你需要perl
:
perl -i -pe "s/<.*?>//g" yourfile
这是一个紧凑的方法。 下面的正则表达式将把你的字符串捕获到组1中:
<[^>]+>|([^<>]*)
我们在这里感兴趣的不是总体比赛,而只是第一组比赛。
所以我们需要遍历组1匹配。 我不用Perl编写代码,但是遵循perlretut教程的配方,应该这样做:
while ($x =~ /<[^>]+>|([^<>]*)/g) { print "$1","\n"; }
请尝试一下,让我知道,如果它适合你。