2

我正在将SMAPI语法转换为JSGF。它们是在不同语音识别系统中使用的非常相似的语法。SMAPI 像世界其他地方一样使用问号,表示前一件事的 0 或 1。JSGF 为此使用方括号。因此,我需要将字符串转换为stuff?to [stuff],并将带括号的字符串转换为((((stuff)? that)? I)? like)?to [[[[stuff] that] I] like]。我必须不理会像((((stuff) that) I) hate). 正如 Qtax 指出的那样,一个更复杂的示例将(foo ((bar)? (baz))?)被替换为(foo [[bar] (baz)]).

因此,我必须提取括号表达式的每一层,看看它是否以问号结尾,如果是,则用方括号替换括号和问号。我认为 Eric Strom 对这个问题的回答几乎就是我所需要的。问题是当我使用它时,它返回最大的匹配分组,而我需要对每个单独的分组进行操作。

这是我到目前为止所拥有的:s/( \( (?: [^()?]* | (?0) )* \) ) \?/[$1]/xg。然而,当与 匹配时((((stuff)? that)? I)? like)?,它只产生[((((stuff)? that)? I)? like)]. 关于如何做到这一点的任何想法?

一世

4

3 回答 3

4

您还需要查看ysth 对该问题的解决方案,并使用已经可用的工具来解决此问题:

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
    }
}
于 2012-06-25T17:29:19.577 回答
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

于 2012-06-25T18:23:15.263 回答
1

您可以通过多种方式解决它,最简单的方法是执行您的表达式,直到不再进行替换。例如:

1 while s/( \( (?: [^()?]* | (?0) )* \) ) \?/[$1]/xg;

但这是非常低效的(对于深度嵌套的字符串)。

您可以像这样一次性完成:

s{
  (?(DEFINE)
    (?<r>   \( (?: [^()]++ | (?&r) )*+ \)   )
  )

  ( \( )
  (?=   (?: [^()]++ | (?&r) )*+ \) \?   )

  |

  \) \?
}{
  $2? '[': ']'
}gex;
于 2012-06-25T17:18:03.327 回答