Perl регулярное выражение в регулярном выражении

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

while($str =~ s/"([^"])+"//){
   $temp = $1;
   $temp2 = $temp;
   $temp =~ s/ /_/g;
   $str =~ s/$temp2/$temp1/;
}

Это также кажется возможным:

$str =~ s/"([^"])+"/replace_spaces($1)/gx;
sub replace_spaces(){
    $word = shift;
    $word =~ s/ /_/g;
    return $word;
}

Есть ли чистый способ регулярного выражения сделать это, как-то вложив регулярное выражение в регулярное выражение?

3 ответа

Для конкретной задачи вам будет лучше использовать Text:: ParseWords:

#!/usr/bin/env perl

use strict; use warnings;
use feature 'say';
use Text::ParseWords;

my $input = q{This is "a t e s t " string. "Hello - world  !"};
my @words = shellwords $input;

for my $word ( @words ) {
    $word =~ s/ +//g;
    say "'$word'";
}

См. Также Как я могу разделить строку, ограниченную [символами], кроме случаев, когда внутри [символ]?

Да, вы можете сделать это, но в каждой ситуации вам нужно изобретать новое регулярное выражение. В этом случае серебряной пули нет.

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

Например:

$ perl -pe 's/(?<=")(\S+)\s+(?=.*")/$1_/g;'
a b "c d" e f
a b "c_d" e f

Но это далеко не идеально. Это работает в самых простых ситуациях. Это не решение, это просто демонстрация идеи.

Вы можете попробовать:

   $str =~ s{"([^"]+)"}{do{(local$_=$1)=~y/ /_/;$_}}eg;

Или для лучшей читаемости:

   $str =~ s/
             "([^"]+)"     # all inside double quotes to $1
            / do{          # start a do block
                 local $_ = $1; # get a copy from $1
                 y| |_|;        # transliterate ' ' to '_'
                 $_             # return string from block
                }          # end the do block
            /xeg;

С уважением

БВ

Другие вопросы по тегам