замена регулярных выражений в Perl - PullRequest
0 голосов
/ 15 ноября 2011

Я не смог понять, как справиться с конкретной проблемой регулярных выражений.

Скажем, у меня есть большая строка, которая состоит из множества фраз в квадратных скобках.Метка фразы (например, S или VP), токен (например, w или wSf), косая черта рядом с этим токеном и затем описание токена (например, CC или VBD_MS3).

Итак, вот пример строки:

[S w#/CC] [VP mSf/VBD_MS3]

Я хочу удалить всю первую фразу в квадратных скобках и поместить в нее w со второй фразой, например:

[VP wmSf/VBD_MS3]

Это возможно даже при использовании регулярных выражений?


Редактировать: Хорошо, шаблон:

[ <label> w#/<label>] [<label> <word>/<label> <word>/<label> <word>/<label>...]

(вторая фраза в скобках может содержать от одного до любого числа / пар)

, где может быть любойпоследовательность заглавных букв, которая может включать в себя подчеркивание, а слово может представлять собой последовательность всего, что не является пробелом (например, цифры / символы / специальные символы).

Ответы [ 4 ]

1 голос
/ 15 ноября 2011

Вместо того, чтобы создавать магическое регулярное выражение для выполнения всей работы, почему бы не разделить строку на фразы, оперировать ими и вернуть их.Это следует той же логике, которую вы только что объяснили.

Это тогда чище, более читабельно (особенно если вы добавляете комментарии) и надежнее.Конечно, вам нужно будет приспособиться к вашим потребностям: например, вы можете захотеть разделить отдельные части / на пары ключ / значение (имеет ли значение порядок? Если не создать хэш-ссылку);возможно, вам не нужно разделять на /, если вам никогда не нужно изменять метку;и т. д.

Редактировать по комментариям: буквально w предшествует #, сохраняет его, удаляет фразу, а затем прикрепляет w к следующей фразе.Если это то, что вам нужно, то имейте это.Конечно, я уверен, что есть крайние случаи, на которые стоит обратить внимание, поэтому сначала сделайте резервную копию и протестируйте!

#!/usr/bin/env perl

use strict;
use warnings;

while( my $line = <DATA> ) {
  #separate phrases, then split phases into whitespace separated pieces
  my @phrases = map { [split /[\s]/] } ($line =~ /\[([^]]+)\]/g);

  my $holder; # holder for 'w' (not really needed if always 'w')
  foreach my $p (@phrases) { # for each phrase
    if ($p->[1] =~ /(w)#/) { # if the second part has 'w#'
      $holder = $1; # keep the 'w' in holder
      $p = undef; #empty to mark for cleaning later
      next; #move to next phrase
    }

    if ($holder) { #if the holder is not empty
      $p->[1] = $holder . $p->[1]; # add the contents of the holder to the second part of this phrase
      $holder = undef; # and then empty the holder
    }
  }

  #remove emptied phrases
  @phrases = grep { $_ } @phrases;

  #reconstitute the line
  print join( ' ', map { '[' . join(' ', @$_) . ']' } @phrases), "\n";
}

__DATA__
[S w#/CC] [VP mSf/VBD_MS3]

Опять же, может показаться удивительным, что вы можете сделать с одним регулярным выражением, но что произойдет, если ваш боссприходит и говорит: «Вы знаете, что то, что вы написали для X, прекрасно работает, но теперь нужно сделать и Y».Вот почему мне нравится вести отдельную логику для каждого логического шага.

1 голос
/ 15 ноября 2011

Не зная действительной формы или позиций, одна из этих форм может работать (не проверено):

s{\[S (\w+)#/\w+\] (\[VP )(\w+/\w+\])}{$2$1$3}g
или
s{\[(?:S/VP) (\w+)#/\w+\] (\[(?:S/VP) )(\w+/\w+\])}{$2$1$3}g
или
s{\[(?:S/VP)\s+(\w+)#/\w+\]\s+(\[(?:S/VP)\s+)(\w+/\w+\])}{$2$1$3}g

Редактировать Так как ваши изменения включили этот шаблон
[ <label> w#/<label>] [<label> <word>/<label> <word>/<label> <word>/<label>...]
это упрощает поиск регулярного выражения, которое должно работать.

Удачи!

use strict;
use warnings;


$/ = undef;

my $data = <DATA>;


my $regex = qr{

      \[\s*                         #= Start of token phrase '['
          (?&label) \s+                 # <label> then whitespace's
          ((?&word))                    # Capture $1 - token word, end grp $1
          [#]/(?&label)                   # '#'/<label>
          \s*
      \]                            #= End of token phrase ']'
      \s*
    (                             # Capture grp $2
      \[\s*                         #= Start of normal phrase '['
          (?&label) \s+                 # <label> then whitespace's
    )                             # End grp $2
    (                             # Capture grp $3
          (?&word)/(?&label)            # First <word>/<label> pair
          (?:                     
             \s+(?&word)/(?&label)      # Optional, many <word>/<label> pair's
          )*                      
          \s*
      \]                            #= End of normal phrase ']'
    )                             # End grp $3

   (?(DEFINE)               ## DEFINE's:
     (?<label> \w+)             # <label> - 1 or more word characters
     (?<word>  [^\s\[\]]+ )     # <word>  - 1 or more NOT whitespace, '[' nor ']'
   )
}x;


$data =~ s/$regex/$2$1$3/g;

print $data;

__DATA__

[S w#/CC] [VP mSf/VBD_MS3]

Выход:
[VP wmSf/VBD_MS3]

Edit2
"если метка символа - PP, а метка следующей фразы - NP, то при присоединении также поменяйте метку следующей фразы на PP. : [PP wsomething / NN] "

Конечно, не добавляя слишком много новых групп захвата, это можно сделать с помощью обратного вызова.
На самом деле, есть много способов сделать это, включая условные выражения регулярных выражений. Я думаю, что
Простейший метод - это обратный вызов, в котором можно принять логику для всех решений с метками.

use strict;
use warnings;


$/ = undef;

my $data = <DATA>;


my $regex = qr{

   ( \[\s*                  # 1 - Token phrase label
         (?&label)         
         \s+
   )
         (                  # 2 - Token word
            (?&word)
         )         
         [#]/(?&label)
         \s*
     \]
     \s*

   ( \[\s*                  # 3 - Normal phrase label
         (?&label)
         \s+
   )
      # insert token word ($2) here
   (                        # 4 - The rest ..
         (?&word)/(?&label)
         (?: \s+ (?&word)/(?&label) )*                      
         \s*
      \]
   )

   (?(DEFINE)               ## DEFINE's:
     (?<label> \w+)             # <label> - 1 or more word characters
     (?<word>  [^\s\[\]]+ )     # <word>  - 1 or more NOT whitespace, '[' nor ']'
   )
}x;


$data =~ s/$regex/ checkLabel($1,$3) ."$2$4"/eg;


sub checkLabel
{
   my ($p1, $p2) = @_;
   if ($p1 =~ /\[\s*PP\s/ && $p2 =~ /(\[\s*)NP(\s)/) {
      return $1.'PP'.$2;
      # To use the formatting of the token label, just 'return $p1;'
   }
   return $p2;
}


print $data;

__DATA__

[PP w#/CC] [ NP     mSf/VBD_MS3]
1 голос
/ 15 ноября 2011

Да,

s|\[S w#/CC\] \[(VP) (mSf/VBD_MS3)\]|[$1 w$2]|;

Теперь, какие шаблоны вы ищете?

Вы могли бы даже сделать это:

s|\[S (w)#/CC\] \[(VP) (mSf/VBD_MS3)\]|[$2 $1$3]|;
0 голосов
/ 15 ноября 2011
#/usr/bin/env perl
use strict;
use warnings;
my $str = "[S w#/CC] [VP mSf/VBD_MS3]";
$str =~ s{\[S w#/CC\]\s*(\[VP\s)(.+)}{$1w$2} and print $str;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...