如何将一个单词标记为单词中不完整包含的标记?

时间:2011-12-14 10:03:39

标签: regex perl token

我理解如何以下列方式在Perl中使用正则表达式:

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

据我所知,如果表达式的任何部分括在括号中,可以在替换部分中使用和捕获它,如下所示:

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

但是有没有办法捕获正则表达式之外的以上的($1)

我有一个完整的单词,这是一串辅音,例如bEdmA,其元音化版本baEodamaA(其中ao为元音),以及由空格分隔的两个标记的分割形式bEd maA 。我想从完整的单词中选择标记的元音形式,如:beEodamaA。我试图在完整的单词表达式中捕获令牌,所以我有:

$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的标记maAbEd,我如何捕获元音序列mAbeEodamaA


修改

我从所有答案中意识到我错过了两个重要细节。

  1. 元音可选。因此,如果令牌是:“Al”和“ywm”,并且完全元音化的单词是“Alyawmi”,那么输出标记将是“Al”和“yawmi”。
  2. 我只提到了两个元音,但还有更多,包括由两个字符组成的符号,如'~a'。完整列表(虽然我认为我不需要在这里提及)是:

    @vowels =('a','我','你','o','〜','〜一','〜我','〜你','N','F', 'K','~N','〜K');

5 个答案:

答案 0 :(得分:1)

以下似乎可以做你想做的事:

#!/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";
}

答案 1 :(得分:0)

在所谓的“列表上下文”中使用m//运算符,如下所示:

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

答案 2 :(得分:0)

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;

在正则表达式中not require capturing groups

答案 3 :(得分:0)

我怀疑有一种更简单的方法可以做任何你想要完成的事情。诀窍不是让正则表达式代码变得如此棘手,以至于你忘记了它实际上在做什么。

我只能开始猜测你的任务,但从你的单个例子看,你好像要检查两个子字符是否在更大的标记中,忽略了某些字符。我猜这些子标记必须是有序的,除了那些元音字符之外,它们之间不能有任何其他东西。

为了匹配标记,我可以在标量上下文中使用带有\G全局标志的/g锚点。这会将匹配锚定到同一标量的最后一个匹配结束后的字符1。这种方式允许我为每个子令牌分别设置模式。这更容易管理,因为我只需要更改@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标志不是模式标志。它必须与运营商合作。

当我没有将所有内容都包装在一个正则表达式中时,我发现管理不断变化的需求要容易得多。

答案 4 :(得分:-1)

假设令牌需要按顺序出现,并且它们之间没有任何东西(除了元音之外):

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;