Я бы просто обошел всю проблему и в то же время упростил код:
my $i = 0;
while ($fileContents =~ s/(.*Part[^\}]*\})//) {
$defParts[$i] = $1;
$i = $i + 1;
}
Здесь мы просто сначала делаем замену. Если это удастся, он все равно установит $1
и вернет true (точно так же, как обычный /.../
), поэтому нет необходимости возиться с s/$1//
позже.
Использование $1
(или любой переменной) в качестве шаблона будет означать, что вы должны экранировать все метасимволы регулярных выражений (например, *
, +
, {
, (
, |
и т. Д.), Если Вы хотите, чтобы это соответствовало буквально. Вы можете сделать это довольно легко с помощью quotemeta
или встроенного (s/\Q$1//
), но это все еще дополнительный шаг и, следовательно, подверженный ошибкам.
Кроме того, вы можете оставить свой оригинальный код и не использовать s///
. Я имею в виду, вы уже нашли совпадение. Зачем использовать s///
для его повторного поиска?
while ($fileContents =~ /(.*Part[^\}]*\})/) {
...
substr($fileContents, $-[0], $+[0] - $-[0], "");
}
Мы уже знаем, где находится совпадение в строке. $-[0]
- это позиция начала, а $+[0]
- позиция конца последнего совпадения с регулярным выражением (таким образом, $+[0] - $-[0]
- это длина совпадающей строки). Затем мы можем использовать substr
для замены этого фрагмента на ""
.
Но давайте продолжим с s///
:
my $i = 0;
while ($fileContents =~ s/(.*Part[^\}]*\})//) {
$defParts[$i] = $1;
$i++;
}
$i = $i + 1;
можно уменьшить до $i++;
(«приращение $ i»).
my @defParts;
while ($fileContents =~ s/(.*Part[^\}]*\})//) {
push @defParts, $1;
}
Единственная причина, по которой нам нужно $i
, - добавить элементы в массив @defParts
. Мы можем сделать это, используя push
, поэтому нет необходимости поддерживать дополнительную переменную. Это спасает нас от другой линии.
Теперь нам, вероятно, не нужно уничтожать $fileContents
. Если замена существует только в интересах этого цикла (поэтому я не сопоставляю уже извлеченный контент), мы можем сделать лучше:
my @defParts;
while ($fileContents =~ /(.*Part[^\}]*\})/g) {
push @defParts, $1;
}
Использование /g
в скалярном контексте добавляет «текущую позицию» к $fileContents
, поэтому следующая попытка совпадения начинается там, где прервано предыдущее совпадение. Это, вероятно, более эффективно, потому что не нужно переписывать $fileContents
.
my @defParts = $fileContents =~ /(.*Part[^\}]*\})/g;
... Или мы могли бы просто использовать //g
в контексте списка, где он возвращает список всех захваченных групп всех совпадений, и присвоить его @defParts
.
my @defParts = $fileContents =~ /.*Part[^\}]*\}/g;
Если в регулярном выражении нет групп захвата, //g
в контексте списка возвращает список всех совпадающих строк (как если бы вокруг всего регулярного выражения было (
)
).
Не стесняйтесь выбирать любой из них. : -)