Как я могу токенизировать слово, данное токенам, которые включены в слово не полностью? - PullRequest
4 голосов
/ 14 декабря 2011

Я понимаю, как использовать регулярные выражения в Perl следующим образом:

$str =~ s/expression/replacement/g;

Я понимаю, что если какая-либо часть выражения заключена в скобки, она может быть использована и записана в замещающей части,как это:

$str =~ s/(a)/($1)dosomething/;

Но есть ли способ получить ($1) выше вне выражения регулярного выражения?

У меня есть полное слово, которое являетсястрока согласных, например, bEdmA, ее гласная версия baEodamaA (где a и o - гласные), а также ее разделенная форма двух жетонов, разделенных пробелом, bEd maA.Я хочу просто взять гласную форму токенов из полного слова, например: beEoda, maA.Я пытаюсь захватить токен в выражении полного слова, поэтому у меня есть:

$unvowelizedword = "bEdmA";
$tokens[0] = "bEd", $tokens[1] = "mA";
$vowelizedword = "baEodamA";

foreach $t(@tokens) {
    #find the token within the full word, and capture its vowels
}

Я пытаюсь сделать что-то вроде этого:

$vowelizedword = m/($t)/;

Это совершенно неправильнопо двум причинам: токен $t не представлен точно в своей собственной форме, такой как bEd, но что-то вроде m/b.E.d/ будет более уместным.Кроме того, как мне записать это в переменную вне регулярного выражения?

Реальный вопрос: как я могу захватить гласные последовательности baEoda и maA, учитывая токеныbEd, mA от полного слова beEodamaA?


Edit

Из всех ответов я понял, что пропустил две важные детали.

  1. Гласные необязательно .Поэтому, если токены: «Al» и «ywm», а полностью гласное слово «Alyawmi», то выходные токены будут «Al» и «yawmi».
  2. Я только упомянулдве гласные, но есть и другие, в том числе символы, состоящие из двух символов, например «~ a».Полный список (хотя я не думаю, что мне нужно упоминать это здесь):

    @ vowels = ('a', 'i', 'u', 'o', '~', '~ a ',' ~ i ',' ~ u ',' N ',' F ',' K ',' ~ N ',' ~ K ');

Ответы [ 5 ]

1 голос
/ 14 декабря 2011

Следующее, кажется, делает то, что вы хотите:

#!/usr/bin/env perl
use warnings;
use strict;

my @tokens = ('bEd', 'mA');
my $vowelizedword = "beEodamaA";

my @regex = map { join('.?', split //) . '.?' } @tokens;

my $regex = join('|', @regex);
$regex = qr/($regex)/;

while (my ($matched) = $vowelizedword =~ $regex) {
    $vowelizedword =~ s{$regex}{};
    print "matched $matched\n";
}

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

#!/usr/bin/env perl
use warnings;
use strict;

my @tokens = ('bEd', 'mA', 'Al', 'ywm');
my $vowelizedword = "beEodamaA Alyawmi"; # Caveat: Without the space it won't work.

my @regex = map { join('.?', split //) . '.?$' } @tokens;

my $regex = join('|', @regex);
$regex = qr/($regex)/;

while (my ($matched) = $vowelizedword =~ $regex) {
        $vowelizedword =~ s{$regex}{};
            print "matched $matched\n";
}
0 голосов
/ 14 декабря 2011

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

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

Чтобы сопоставить токены, я могу использовать якорь \G с глобальным флагом /g в скалярном контексте. Это привязывает совпадение к персонажу после окончания последнего совпадения для того же скаляра. Этот способ позволяет мне иметь отдельные шаблоны для каждого вспомогательного токена. Это намного проще в управлении, поскольку мне нужно всего лишь изменить список значений в @subtokens.

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

use v5.14;

my $vowels    = '[ao]*';
my @subtokens = qw(bEd mA);

# prepare the subtoken regular expressions
my @patterns = map {
    my $s = join "$vowels", map quotemeta, (split( // ), '');
    qr/$s/;
    } @subtokens;

my @tokens = qw( baEodamA mAabaEod baEoda mAbaEoda );

my @grand_matches;
TOKEN: foreach my $token ( @tokens ) {
    say "-------\nMatching $token..........";
    my @matches;
    PATTERN: foreach my $pattern ( @patterns ) {
        say "Position is ", pos($token) // 0;

        # scalar context /g and \G
        next TOKEN unless $token =~ /\G($pattern)/g; 
        push @matches, $1;
        say "Matched with $pattern";
        }
    push @grand_matches, [ $token, \@matches ];
    }

# Now report the original   
foreach my $tuple ( @grand_matches ) {
    say "$tuple->[0] has both fragments: @{$tuple->[1]}";
    }

Теперь, вот что хорошо в этой структуре. Я, вероятно, неправильно угадал о вашей задаче. Если у меня есть, это легко исправить без изменения настроек. Допустим, субтокены не должны быть в порядке. Это легко изменить шаблон, который я создал. Я просто избавляюсь от \G якорь и флаг /g;

        next TOKEN unless $token =~ /($pattern)/; 

Или предположим, что жетоны должны быть в порядке, но между ними могут быть другие вещи. Я могу вставить .*?, чтобы соответствовать этому материалу, фактически пропуская его:

        next TOKEN unless $token =~ /\G.*?($pattern)/g; 

Было бы намного лучше, если бы я мог справиться со всем этим с map, где я создаю шаблоны, но флаг /g не является флагом шаблона. Это должно идти с оператором.

Мне гораздо легче управлять изменяющимися требованиями, когда я не заключаю все в одно регулярное выражение.

0 голосов
/ 14 декабря 2011

Предполагая, что токены должны появляться в порядке и без чего-либо (кроме гласной) между ними:

my @tokens = ( "bEd", "mA" );
my $vowelizedword = "baEodamaA";

my $vowels = '[ao]';
my (@vowelized_sequences) = $vowelizedword =~ ( '^' . join( '', map "(" . join( $vowels, split( //, $_ ) ) . "(?:$vowels)?)", @tokens ) . '\\z' );
print for @vowelized_sequences;
0 голосов
/ 14 декабря 2011

ETA: Из того, что я сейчас понимаю, вы пытались сказать, что вы хотите сопоставить дополнительный гласный после каждого символа токенов.

С этим вы можетенастройте переменную $vowels, чтобы она содержала только буквы, которые вы ищете.При желании вы также можете просто использовать . для захвата любого символа.

use strict;
use warnings;
use Data::Dumper;

my @tokens = ("bEd", "mA");
my $full = "baEodamA";

my $vowels = "[aeiouy]";
my @matches;
for my $rx (@tokens) {
    $rx =~ s/.\K/$vowels?/g;
    if ($full =~ /$rx/) {
        push @matches, $full =~ /$rx/g;
    }
}

print Dumper \@matches;

Выход:

$VAR1 = [
          'baEoda',
          'mA'
        ];

Обратите внимание, что

... $full =~ /$rx/g;

не не требует захвата групп в регулярном выражении.

0 голосов
/ 14 декабря 2011

Используйте оператор m// в так называемом «контексте списка», как это:

my @tokens = ($input =~ m/capturing_regex_here/modifiershere);

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...