Perl заменяет n-ю подстроку в строке - PullRequest
3 голосов
/ 22 июля 2011

У меня есть сценарий, в котором мне нужно заменить n-ю подстроку в строке.

s/sub-string/new-string/g; заменит все подстроки, но мне нужно сделать для конкретного случая.

Пожалуйста, помогите мне с этим.

Ответы [ 6 ]

3 голосов
/ 22 июля 2011

Для замены n-го вхождения строки с помощью sed вы можете использовать эту команду:

sed 's/find_string/replace_string/n'

Для замены подстроки нам нужно знать, что вы хотите заменить.Приведите пример.

1 голос
/ 22 июля 2011

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

my $string = "one two three four five";

$string =~ m/\w+\s*/g for 1 .. 2;
substr( $string,pos($string) ) =~ s/(\w+)/3/;
print "$string\n";

Использование m//g в скалярном контексте приводит к тому, что оно совпадает один раз за итерацию цикла for. На каждой итерации pos() отслеживает окончание самого последнего подстатья на $string. После того как вы прошли 'n' итераций (в нашем случае две), вы можете подключить pos() к substr(). Используйте substr($string... в качестве lvalue. Это заставит совпадение регулярного выражения начинаться с любой позиции, которую вы указали во втором аргументе. Мы подключаем туда pos, что заставляет его брать следующий матч везде, где остановился последний матч.

Этот подход исключает явный счетчик (хотя цикл for, по сути, одно и то же без указания переменной счетчика). Этот подход также масштабируется лучше, чем подход s//condition ? result : result/eg, потому что он остановится после того, как будет выполнено третье совпадение, вместо того, чтобы продолжать попытки сопоставления, пока не будет достигнут конец потенциально большой строки. Другими словами, подход s///eg не ограничивает сопоставление, он только условно имеет дело с результатом сколь угодно большого числа успешных совпадений.

В предыдущем вопросе на ту же тему я однажды вставил счетчик в левой части оператора s ///. Хотя это работает для этого конкретного случая, это не идеальное решение, потому что оно склонно к отказу от обратного. Это еще один случай, когда простота была бы лучшим подходом. Я упоминаю об этом здесь, чтобы вы могли избежать соблазна попробовать такую ​​хитрость (если только вы не хотите повеселиться с возвратом).

Подход, который я опубликовал здесь, я считаю, очень ясен; вы смотрите на это и знаете, что происходит: совпадать дважды, отслеживать последнюю позицию матча, теперь сопоставлять в третий раз с заменой. У вас может быть умный, у вас может быть эффективный, и у вас может быть ясный. Но иногда вы не можете иметь все три. Здесь вы получаете эффективный и ясный.

1 голос
/ 22 июля 2011

Этот вопрос может быть интересен: Perl regex replace count

Вы можете сделать что-то вроде этого:

use strict;
use warnings;

my $count = 3;
my $str = "blublublublublu";
$str =~ s/(lu)/--$count == 0 ? "LA":$1/ge;
print $str;
1 голос
/ 22 июля 2011

Вы также можете сделать это

my $i=0;
s/(old-string)/++$i%3 ? $1 : "new_string"/ge;
1 голос
/ 22 июля 2011

Попробуйте это:

 s/((old-string).*?){2}\2/\1\1new-string/
1 голос
/ 22 июля 2011

Попробуйте:

s/(sub-string{2,2})sub-string/$1new-string/

настроить 2 в соответствии с вашими потребностями (это ваш 'n'- 1).Обратите внимание, что между этими подстроками не может быть разделителей.например, «abcabcabc» будет работать, но «abcdefabcabc» не будет

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