我正在将SMAPI语法转换为JSGF。它们是用于不同语音识别系统的非常相似的语法。 SMAPI使用与世界其他地方相同的问号,表示前一个问题的0或1。 JSGF使用方括号。因此,我需要将stuff?
之类的字符串转换为[stuff]
,并将((((stuff)? that)? I)? like)?
括起来的字符串转换为[[[[stuff] that] I] like]
。我必须留下像((((stuff) that) I) hate)
这样的字符串。正如Qtax指出的那样,一个更复杂的例子是(foo ((bar)? (baz))?)
被(foo [[bar] (baz)])
取代。
因此,我必须提取带括号的表达式的每个级别,看它是否以问号结尾,并用方括号替换parens和问号(如果有)。 我认为Eric Strom对this问题的回答几乎就是我所需要的。问题是,当我使用它时,它返回最大的匹配分组,而我需要对每个单独的分组进行操作。
这是我到目前为止所做的:s/( \( (?: [^()?]* | (?0) )* \) ) \?/[$1]/xg
。但是,与((((stuff)? that)? I)? like)?
匹配时,它只会生成[((((stuff)? that)? I)? like)]
。关于如何做到这一点的任何想法?
我
答案 0 :(得分:4)
您还需要查看ysth's solution to that question,并使用已有的工具来解决此问题:
use Text::Balanced qw(extract_bracketed);
$text = '((((stuff)? that)? I)? like)?';
for ($i=0; $i<length($text); $i++) {
($match,$remainder) = extract_bracketed( substr($text,$i), '()' );
if ($match && $remainder =~ /^\?/) {
substr($text,$i) =
'[' . substr($match,1,-1) . ']' . substr($remainder,1);
$i=-1; # fixed
}
}
答案 1 :(得分:2)
在较旧的Perl版本(5.10之前版本)中,可以使用代码断言和动态正则表达式:
...
my $s = '((((stuff)? that)? I)? like)?';
# recursive dynamic regex, we need
# to pre-declare lexical variables
my $rg;
# use a dynamically generated regex (??{..})
# and a code assertion (?{..})
$rg = qr{
(?: # start expression
(?> [^)(]+) # (a) we don't see any (..) => atomic!
| # OR
( # (b) start capturing group for level
\( (??{$rg}) \) \? # oops, we found parentheses \(,\) w/sth
) # in between and the \? at the end
(?{ print "[ $^N ]\n" }) # if we got here, print the captured text $^N
)* # done, repeat expression if possible
}xs;
$s =~ /$rg/;
...
在比赛期间,代码断言打印所有匹配,即:
[ (stuff)? ]
[ ((stuff)? that)? ]
[ (((stuff)? that)? I)? ]
[ ((((stuff)? that)? I)? like)? ]
要根据您的要求使用它,您可以稍微更改代码断言,将捕获括号放在正确的位置,并将匹配保存在数组中:
...
my @result;
my $rg;
$rg = qr{
(?:
(?> [^)(]+)
|
\( ( (??{$rg}) ) \) \? (?{ push @result, $^N })
)*
}xs;
$s =~ /$rg/ && print map "[$_]\n", @result;
...
说:
[stuff]
[(stuff)? that]
[((stuff)? that)? I]
[(((stuff)? that)? I)? like]
此致
RBO
答案 2 :(得分:1)
您可以通过几种方式解决它,最简单的方法就是执行您的表达式,直到不再进行替换。 E.g:
1 while s/( \( (?: [^()?]* | (?0) )* \) ) \?/[$1]/xg;
但这非常低效(对于深度嵌套的字符串)。
你可以在这样的一次传球中代替:
s{
(?(DEFINE)
(?<r> \( (?: [^()]++ | (?&r) )*+ \) )
)
( \( )
(?= (?: [^()]++ | (?&r) )*+ \) \? )
|
\) \?
}{
$2? '[': ']'
}gex;