我在方括号内有大块字符串,如下所示:
[p1 text1/label1] [p2 text2/label2] [p3 text3/label3] [...
Run Code Online (Sandbox Code Playgroud)
等等.
每个块内部的内容并不重要.但有时会有一些没有方括号包围的杂散文本块.例如:
[p1 text1/label1] [p2 text2/label2] textX/labelX [p3 text3/label3] [...] textY/labelY textZ/labelZ [...]
Run Code Online (Sandbox Code Playgroud)
我以为我用Perl中的正则表达式解决了这个问题,直到我意识到我只是迎合了文本的开头,中间或末尾有一个流浪文本的情况,但不是我们可能有两个流浪案件在一起.(比如上面的Y和Z块).
所以我意识到perl中的正则表达式只捕获第一个匹配模式?那怎么可以解决上面的问题呢?
问题是确保所有都应该用括号括起来.方括号永远不会递归.用括号括住短语时,p值取决于"标签"值.例如,如果一个流浪的未括号的短语是
li/IN
Run Code Online (Sandbox Code Playgroud)
然后它应该变成:
[PP li/IN]
Run Code Online (Sandbox Code Playgroud)
我想这是一个混合,但我能想到解决我正在研究的更大问题的唯一方法是将所有这些问题变成括号中的短语,这样处理就更容易了.所以如果在开头,中间和结尾都有一个没有括号的短语,我就可以使用它,但如果两个或多个一起发生则不会.
我基本上为每个位置(开始,中间和结束)使用了不同的正则表达式.在中间捕获一个未加括号的短语的那个看起来像这样:
$data =~ s/\] (text)#\/label \[/\] \[selected-p-value $1#\/label\] \[/g;
Run Code Online (Sandbox Code Playgroud)
所以我正在做的只是注意到如果一个]出现在文本/标签模式之前和之后,那么这个没有括号.我也为其他人做类似的事情.但我想这是非常不通用的.我的正则表达不是很好!
#!/usr/bin/perl
use strict;
use warnings;
my $string = "[p1 text1/label1] [p2 text2/label2] textX/labelX [p3 text3/label3] [...] textY/labelY textZ/labelZ [...]";
# don't split inside the [], i.e. not at blanks that have p\d in front of them
my @items = split(/(?<!p\d)\s+/, $string);
my @new_items;
# modify the items that are not inside []
@new_items = map { ($_ =~ m/\[/) ? $_ :
((split("/",$_))[1] eq ("IN")) ? "[PP $_]" :
"[BLA $_]";
} @items;
print join(' ', @new_items), "\n";
Run Code Online (Sandbox Code Playgroud)
这给了
[p1 text1/label1] [p2 text2/label2] [PP textX/labelX] [p3 text3/label3] [...] [PP textY/labelY] [PP textZ/labelZ] [...]
Run Code Online (Sandbox Code Playgroud)
我把它PP
当作我在这里使用的意思,否则map
必须变得更加精细.
编辑
我已经编辑了代码以回应您的评论.如果你使用
"[p1 text1/label1] [p2 text2/label2] textX/IN [p3 text3/label3] [...] textY/labelY textZ/labelZ [...]";
Run Code Online (Sandbox Code Playgroud)
作为示例字符串,这是输出:
[p1 text1/label1] [p2 text2/label2] [PP textX/IN] [p3 text3/label3] [...] [BLA textY/labelY] [BLA textZ/labelZ] [...]
Run Code Online (Sandbox Code Playgroud)
只需记住一件事:使用的正则表达式split
不适用于pn
n> 9.如果你有这样的情况,最好寻找替代方案,因为可变长度的lookbehinds尚未实现(或者至少在我的Perl版本中) (5.10.1)他们没有).
编辑2
作为对第二条评论的回复,这是脚本的修改版本.您会发现我还在示例字符串中添加了一些内容,以证明它现在可以正常运行,即使pn
内部没有[...]
.
#!/usr/bin/perl
use strict;
use warnings;
my $string = "[p1 text1/label1] [p2 text2/label2] textX/IN [p3 text3/label3] [...] textY/labelY textZ/labelZ [...] xyx/IN [opq rs/abc]";
# we're using a non-greedy match to only capture the contents of one set of [],
# otherwise we'd simply match everything between the first [ and the last ].
# The parentheses around the match ensure that our delimiter is KEPT.
my @items = split(/(\[.+?\])/, $string);
#print "..$_--\n" for @items; # uncomment this to see what the split result looks like
# modify the items that are not inside []
my @new_items = map {
if (/^\[/) { # items in []
$_;
}
elsif (/(?: \w)|(?:\w )/) { # an arbitrary number of items without []
my @new = map { ($_ =~ m/\[/) ? $_ :
((split("/",$_))[1] eq ("IN")) ? "[PP $_]" :
"[BLA $_]";
} split;
}
else { # some items are '', let's just discard those
}
} @items;
print join(' ', @new_items), "\n";
Run Code Online (Sandbox Code Playgroud)
输出是这样的:
[p1 text1/label1] [p2 text2/label2] [PP textX/IN] [p3 text3/label3] [...] [BLA textY/labelY] [BLA textZ/labelZ] [...] [PP xyx/IN] [opq rs/abc]
Run Code Online (Sandbox Code Playgroud)
我注意到你已经收到了你需要的帮助,但我想我可以回答你的问题......
实际上你可以使用“仅”正则表达式来解决这个问题:
#!/usr/bin/perl
use strict;
use warnings;
$_ = "[p1 text1/label1] [p2 text2/label2] textX/labelX [p3 text3/label3] [...] textY/labelY textZ/labelZ [...]";
s{ ([^\s[]+)|(\[(?:[^[]*)\]) }
{ if( defined $2){ $2 } elsif(defined $1)
{
if($1 =~ m!(.*(?<=/)(.*))!)
{
if($2 eq 'labelX')
{
"[PP $1]";
}
elsif($2 eq 'labelY')
{
"[BLA $1]";
}
elsif($2 eq 'labelZ')
{
"[FOO $1]";
}
}
}
}xge;
print;
Run Code Online (Sandbox Code Playgroud)
输出 :
[p1 text1/label1] [p2 text2/label2] [PP textX/labelX] [p3 text3/label3] [...] [BLA textY/labelY] [FOO textZ/labelZ] [...]
Run Code Online (Sandbox Code Playgroud)