Perl:Regex获取重复模式之间的所有文本
我想为以下内容创建一个正则表达式 我有一些文字如下:Perl:Regex获取重复模式之间的所有文本,regex,perl,parsing,regexp-grammars,Regex,Perl,Parsing,Regexp Grammars,我想为以下内容创建一个正则表达式 我有一些文字如下: field = "test string"; type = INT; funcCall(.., field, ...); ... text = "desc"; field = "test string 1"; type = FLOAT; funcCall(.., field, ...); ... text = "desc 2"; field = "test string 2"; type = FLOAT; funcCall(.., fi
field = "test string";
type = INT;
funcCall(.., field, ...);
...
text = "desc";
field = "test string 1";
type = FLOAT;
funcCall(.., field, ...);
...
text = "desc 2";
field = "test string 2";
type = FLOAT;
funcCall(.., field, ...);
...
text = "desc 3";
.... keeps repeating
my @overall = ($string =~ m/field\s*=.*?/gis);
基本上,我正在尝试创建一个正则表达式,以获取从第一个“field=”开始到第二个“field=”开始的所有文本。它必须跳过函数调用中使用的字段文本
我目前有以下情况:
field = "test string";
type = INT;
funcCall(.., field, ...);
...
text = "desc";
field = "test string 1";
type = FLOAT;
funcCall(.., field, ...);
...
text = "desc 2";
field = "test string 2";
type = FLOAT;
funcCall(.., field, ...);
...
text = "desc 3";
.... keeps repeating
my @overall = ($string =~ m/field\s*=.*?/gis);
但是,这仅获得文本“field=”。如果没有“?”,它将获取从第一个实例到最后一个实例的所有数据
我还尝试:
my @overall = ($string =~ m/field\s*=.*field\s*=/gis);
然而,这将使我每隔一个实例,因为它是第二个“field=”字符串的所有格。有什么建议吗?这对正则表达式来说很难。幸运的是,这不是你盒子里唯一的工具 看起来每条记录之间都有一条空行。如果是这样,您可以通过将
$/
设置为“\n\n”
轻松完成此操作。然后,您可以通过while循环读取文件,每次迭代$\uuu
都将被设置为您试图处理的块
否则,您可以将其设置为
field=
,或者甚至只使用split
这对于awk
$ awk -v RS= 'NR==1' file
field = "test string";
type = INT;
funcCall(.., field, ...);
...
text = "desc";
使用段落模式,打印第一条记录。快速而肮脏的方法是定义一个主要与字段分配匹配的正则表达式,然后在另一个正则表达式中使用该正则表达式来匹配它们之间的内容
my $field_assignment_re = qr{^\s* field \s* = \s* [^;]+ ;}msx;
$code =~ /$field_assignment_re (.*?) $field_assignment_re/msx;
print $1;
这种方法的缺点是它可能匹配带引号的字符串等
您可以使用正则表达式对代码进行排序,但是正确地解析代码超出了常规正则表达式的范围。这是因为平衡分隔符(即括号和括号)和转义符(即
“我能看到的最简单的方法是通过/^\s*field\s*=/
表达式拆分$string
。如果我们想捕获文本的'field='
部分,我们可以在一个
因此,它在每一行的开头断开,'field'
是下一个非空白字符串,后跟任意数量的空白,后跟一个'='
输出为:
$_=[
field = "test string";
type = INT;
funcCall(.., field, ...);
...
text = "desc";
]
$_=[
]
$_=[
field = "test string 1";
type = FLOAT;
funcCall(.., field, ...);
...
text = "desc 2";
]
$_=[
]
$_=[
field = "test string 2";
type = FLOAT;
funcCall(.., field, ...);
...
text = "desc 3";
.... keeps repeating
]
这几乎是我想要的。但是,它在我们想要的捕获之间留下了一个空白行的伪影。我不知道如何消除它,所以我们只需过滤掉所有空白字符串:
foreach ( grep { m/\S/ } split /(?=^\s*field\s*=)/ms, $string ) {
say "\$_=[\n$_]";
}
然后它产生:
$_=[
field = "test string";
type = INT;
funcCall(.., field, ...);
...
text = "desc";
]
$_=[
field = "test string 1";
type = FLOAT;
funcCall(.., field, ...);
...
text = "desc 2";
]
$_=[
field = "test string 2";
type = FLOAT;
funcCall(.., field, ...);
...
text = "desc 3";
.... keeps repeating
]
您可以使用它。对于示例数据的整体“whipupality”,我认为将模式传递到拆分将是最简单的。但是,正如所指出的,当事情变得更复杂时,使用语法会有所帮助
为了好玩,我创建了一个示例脚本,该脚本使用构建的解析表达式语法来解析您的数据。这两种语法都具有广泛使用和熟悉的优势,可以快速构造语法。如果您已经了解perl,并且需要一个简单但功能强大的正则表达式版本,则入门门槛较低用于项目的表达式。方法是尝试使perl易于构造和使用。使用Pegex,您可以用正则表达式构建解析表达式语法:
“Pegex…通过结合解析表达式语法(PEG)来获得它的名称,
与定期开除(Regex)。这实际上是Pegex所做的。”
()
下面是一个独立的脚本,它使用Pegex语法解析数据的简化版本
首先,脚本将$grammar
“inline”作为多行字符串读取,并使用它来->parse()
从
句柄读取的示例数据。通常,解析语法和数据将驻留在单独的文件中。语法的“”使用pegex
函数将正则表达式编译成用于解析数据的正则表达式的“树”或散列。parse()
方法返回可由perl使用的数据结构。向脚本添加和p$ast
可以帮助您查看哪些结构(,等等)正在由您的语法返回
#!/usr/bin/env perl
use v5.22;
use experimental qw/ refaliasing postderef / ;
use Pegex;
my $data = do { local $/; <DATA> } ;
my $grammar = q[
%grammar thing
%version 0.0.1
things: +thing*
thing: (+field +type +text)+ % end
value: / <DOUBLE> (<ANY>*) <DOUBLE> /
equals: / <SPACE> <EQUAL> <SPACE> /
end: / BLANK* EOL /
field: 'field' <equals> <value> <SEMI> <EOL>
type: 'type' <equals> /\b(INT|FLOAT)\b/ <SEMI> <EOL>
func: / ('funcCall' LPAREN <ANY>* RPAREN ) / <SEMI> <EOL> .( <DOT>3 <EOL>)*
text: 'text' <equals> <value> <SEMI> <EOL>
];
my $ast = pegex($grammar, 'Pegex::Tree')->parse($data);
for \my @things ( $ast->[0]->{thing}->@* ) {
for \my %thing ( @things ) {
say $thing{"text"}[0] if $thing{"text"}[0] ;
say $thing{"func"}[0] if $thing{"func"}[0] ;
}
}
当然,您也可以使用经典的perl方式,或者例如,使用where-we-do,轻松地从文件句柄或STDIN
读取数据:
use IO::All;
my $infile < io shift ; # read from STDIN
使用IO::All;
我的$infle
您可以从开始安装,然后了解Pegex的工作原理
有了Perl6,我们将获得一个功能强大且易于使用的“语法引擎”,它建立在Perl处理正则表达式的优势之上。如果语法开始在更广泛的项目中使用,这些开发必将反馈到perl5中,并带来更强大的功能
Pegex的PEG部分及其跨语言开发允许在不同的编程语言社区(Ruby、Javascript)之间交换语法.Pegex可以在相当简单的场景中使用,并且非常适合需要解析功能的更复杂的模块。Pegex API允许轻松创建规则派生的函数集,这些函数可以在“”中定义。通过receiver类,您可以构建复杂的方法来处理解析的数据,从而“解析时咀嚼”,甚至动态修改语法(!)更多可重复使用和改进的工作语法示例,越来越多使用Pegex
的模块将帮助它变得更加有用和强大
也许试用Pegex框架最简单的方法是-它允许您像regexp一样方便地使用语法,将解析结果存储在%/
中。调用Pegex::Regex
解析表达式语法的“网关药物”,并指出它是“Damian Conway的Regexp::Grammars
module API的克隆(在他对这个问题的回答中包括)
很容易上瘾。对于正则表达式来说,这类问题很难解决。我会
foreach ( grep { m/\S/ } split /(?=^\s*field\s*=)/ms, $string ) {
say "\$_=[\n$_]";
}
$_=[
field = "test string";
type = INT;
funcCall(.., field, ...);
...
text = "desc";
]
$_=[
field = "test string 1";
type = FLOAT;
funcCall(.., field, ...);
...
text = "desc 2";
]
$_=[
field = "test string 2";
type = FLOAT;
funcCall(.., field, ...);
...
text = "desc 3";
.... keeps repeating
]
#!/usr/bin/env perl
use v5.22;
use experimental qw/ refaliasing postderef / ;
use Pegex;
my $data = do { local $/; <DATA> } ;
my $grammar = q[
%grammar thing
%version 0.0.1
things: +thing*
thing: (+field +type +text)+ % end
value: / <DOUBLE> (<ANY>*) <DOUBLE> /
equals: / <SPACE> <EQUAL> <SPACE> /
end: / BLANK* EOL /
field: 'field' <equals> <value> <SEMI> <EOL>
type: 'type' <equals> /\b(INT|FLOAT)\b/ <SEMI> <EOL>
func: / ('funcCall' LPAREN <ANY>* RPAREN ) / <SEMI> <EOL> .( <DOT>3 <EOL>)*
text: 'text' <equals> <value> <SEMI> <EOL>
];
my $ast = pegex($grammar, 'Pegex::Tree')->parse($data);
for \my @things ( $ast->[0]->{thing}->@* ) {
for \my %thing ( @things ) {
say $thing{"text"}[0] if $thing{"text"}[0] ;
say $thing{"func"}[0] if $thing{"func"}[0] ;
}
}
__DATA__
field = "test string 0";
type = INT;
funcCall(.., field, ...);
...
text = "desc 1";
field = "test string 1";
type = FLOAT;
funcCall(.., field, ...);
...
text = "desc 2";
field = "test string 2";
type = FLOAT;
funcCall(.., field, ...);
...
text = "desc 3";
use IO::All;
my $infile < io shift ; # read from STDIN