2012-06-25 3 views
2

Я преобразовываю грамматику 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 и вопросительный знак квадратными скобками, если это произойдет. Я думаю, что ответ Эрика Стром на вопрос this вопрос - это почти то, что мне нужно. Проблема в том, что когда я его использую, он возвращает наибольшую согласованную группировку, тогда как мне нужно делать операции над каждой отдельной группой.

Это то, что у меня есть до сих пор: s/(\((?: [^()?]* | (?0))* \)) \?/[$1]/xg. Однако при сопоставлении с ((((stuff)? that)? I)? like)? он производит только [((((stuff)? that)? I)? like)]. Есть идеи, как это сделать?

I

+3

Вместо регулярного выражения вы можете просто заменить строку заменой '(' '' '' '' '' '' '' '' '' '' '? –

+0

Ваше название говорит, что вам нужно извлечь содержимое круглых скобок, но в вашем тексте вам нужно скопировать круглые скобки в квадратные скобки. Что он? – TLP

+0

Я отредактировал вопрос, чтобы лучше отразить мои намерения. –

ответ

1

Вы могли бы решить эту проблему в несколько способов, простейшим быть просто выполняя ваше выражение, пока нет больше замен сделал. Например:

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

Но это очень неэффективно (для глубоко вложенных строк).

Вы могли бы сделать это за один проход, как это вместо:

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

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

    | 

    \) \? 
}{ 
    $2? '[': ']' 
}gex; 
+0

1, когда все работает отлично! Почему придание регулярному выражению g swith не делало то же самое? Тем не менее, данный ' = (((материал)? That)? I)? Like)?', Ваше регулярное выражение дает мне ' =]]]] материал], который] я] как]' по какой-то причине. –

+0

@NateGlenn, теперь работает, изменил '$ 1' на' $ 2'. (Забыл считать рекурсивную группу, до.) – Qtax

+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 
    } 
} 
+0

@ Оммега, хорошо, как? Эта версия вообще не работает даже с оригинальным примером OPs. (Результат - это [[[[[stuff] that)? I] like] '.) Для этого простого примера работала первая версия, но это не хорошо, так как она терпит неудачу с правильным примером, например' (foo ((bar) ? (baz))?) ', result' (foo [([bar] (baz]?) '. Ничего не работает, -1 до фиксированного. – Qtax

+0

исправлено. – mob

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