Можно ли указать максимальное количество совпадений для замены. Например, если совпадение "l" в "Hello World", можно ли заменить первые 2 'l' символы, но не третье без цикла?
Perl regex заменить count
Ответ 1
$str = "Hello world!";
$str =~ s/l/r/ for (1,2);
print $str;
Я не вижу, что так плохо в цикле.
Собственно, вот путь:
$str="Hello world!";
$str =~ s/l/$i++ >= 2 ? "l": "r"/eg;
print $str;
Это цикл, из-за того, что s///g работает циклично, когда вы это делаете. Но не традиционный цикл.
Ответ 2
Вот один из способов. Для этого требуется, чтобы внешний счетчик обновлялся в RE с использованием блока (?{code})
внутри конструкции (?(condition)true-sub-expression|false-sub-expression)
. См. perldoc perlre для объяснения.
use Modern::Perl;
use re qw/eval/; # Considered experimental.
my $string = 'Hello world!';
my $count = 2;
my $re = qr/
(l)
(?(?{$count--})|(*FAIL))
/x;
say "Looking for $count instances of 'l' in $string.";
my ( @found ) = $string =~ m/$re/g;
say "Found ", scalar @found, " instances of 'l': @found";
Вывод:
Looking for 2 instances of 'l' in Hello world!
Found 2 instances of 'l': l l
Здесь еще один тест того же regexp, но на этот раз мы отслеживаем позицию совпадений, чтобы доказать, что он соответствует первым двум вхождениям.
use Modern::Perl;
use strict;
use warnings;
use re qw/eval/; # Considered experimental.
my $string = 'Hello world!';
my $count = 2;
my $position = 0;
my $re = qr/
(l)(?{$position=pos})
(?(?{$count--})|(*FAIL))
/x;
while( $string =~ m/$re/g ) {
say "Found $1 at ", $position;
}
И на этот раз вывод:
Found l at 3
Found l at 4
Я не думаю, что я порекомендую все это. Если бы я рассматривал ограничение соответствия только одной части строки, я бы соответствовал строке substr()
строки. Но если вам нравится жить на краю, продолжайте и получайте удовольствие от этого фрагмента.
Здесь он находится в подстановке:
use Modern::Perl;
use strict;
use warnings;
use re qw/eval/; # Considered experimental.
my $string = 'Hello world!';
say "Before substitution $string";
my $count = 2;
my $re = qr/
(l)
(?(?{$count--})|(*FAIL))
/x;
$string =~ s/$re/L/g;
say "After substitution $string";
И вывод:
Before substitution Hello world!
After substitution HeLLo world!
Ответ 3
Короткий ответ: нет. Вам нужно будет выполнить замены в какой-то петле.