在perl中,我怎样才能在某些字符序列之后和之前替换?

时间:2016-08-31 19:22:56

标签: regex perl

例如,如果我想将所有出现的双元音替换为单个大写元音,只有它们出现在<begin><end>之间,我该怎么做?

Noot thiis <begin> buut theese need too bee chaanged <end> buut noot heeree eitheer

应该成为

Noot thiis <begin> bUt thEse nEd tO bE chAnged <end> buut noot heeree eitheer 

4 个答案:

答案 0 :(得分:6)

案例<begin><end>的正则表达式可以多次出现:

$_="Noot thiis <begin> buut theese need too bee chaanged <end> buut noot heeree eitheer<begin>and thiis <end>";
s/(?:<begin>|\G(?!^))(?(?=<end>)|.)*?\K([a-z])(\1)/uc($1)/ge;
print;

结果

Noot thiis <begin> bUt thEse nEd tO bE chAnged <end> buut noot heeree eitheer<begin>and thIs <end>

Demo on regex101.com

正则表达式:

(?:<begin>|      # Search from <begin>
   \G            # or position of last match
   (?!^)         #    excluding start of string
)      
(?(?=<end>)|     # If found <end> then test expression between `)` and `|`.
                 # as it is empty (not a <end>)
                 #  - then not matched - end of current search.
  .)*?           # if NOT <end> then any symbol. too many times
\K               # Matched only be considered from this position
                 # replace only after this position
([a-z])(\1)      # 1-character and 1 same

答案 1 :(得分:1)

您可以使用表达式替换,其中表达式是使用非破坏性选项的另一个替换/r

看起来像这样

use strict;
use warnings 'all';
use feature 'say';

my $s = 'Noot thiis <begin> buut theese need too bee chaanged <end> buut noot heeree eitheer';


$s =~ s{(<begin>.*?<end>)}{ $1 =~ s/([aeiou])\g1/uc $1/egr }esg;

say $s;

输出

Noot thiis <begin> bUt thEse nEd tO bE chAnged <end> buut noot heeree eitheer

答案 2 :(得分:0)

我认为您可以首先提取这些标记之间的文本并使用它。

但是,如果你想使用正则表达式,我可以想出这样的正则表达式:

 (.*<begin>)|(<end>.*)|([a-z])\3

替换字符串:

 $1$2$3

<强> Regex demo

当然,您需要将小组$3

大写

enter image description here

答案 3 :(得分:0)

Borodin方法的一点变化,模拟基于正则表达式的替换中的回调方法。标签匹配正则表达式比懒惰点匹配模式更快,因为它符合unroll-the-loop原则。内部替换使用\u uppercasing运算符(使下一个char大写):

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

my $s = 'Noot thiis <begin> buut theese need too bee chaanged <end> buut noot heeree eitheer';
$s =~ s{(<begin>[^<]*(?:<(?!end>)[^<]*)*<end>)}{ $1 =~ s/([eiaou])\1/\u$1/gr }eg;
print $s;

请参阅regex demo

<begin>[^<]*(?:<(?!end>)[^<]*)*<end>模式意味着:

  • <begin> - 匹配文字字符串
  • [^<]* - 除<
  • 以外的零个或多个字符
  • (?:<(?!end>)[^<]*)* - 零个或多个序列:
    • <(?!end>) - <未跟end>
    • [^<]* - 除<
    • 以外的零个或多个字符
  • <end> - 文字文字。

由于使用了否定的字符类,此正则表达式不需要/s DOTALL修饰符,并且它比基于.*?的正则表达式更快,因为否定的字符类会抓取与其模式匹配的整个文本块在没有检查每个后续职位的情况下一气呵成。