2014-10-07 3 views
-1

У меня есть следующий код perl. Я пытаюсь grep путь от ссылок массива и добавлять «\» или «/» в конце и вставлять его в новый массив. Но я не получаю желаемого результата. Что мне не хватает?PERL Regex и добавление

use strict; 

my @links = (
    "incl -s projectA /. /abc/cde/efg", 
    "incl -s projectA \. \hij\klm\nop", 
); 

my ($path, $link, @linkpaths, $op); 
my $substr = "/"; 

foreach $link (@links) { 
    $link =~ m{incl -s projectA /. /|\\.\\(.+)}; 
    $path = $1; 
    print "Path is $path \n"; 
    if (index($path, $substr) != -1) { 
     print "$link contains $substr\n"; 
     $op = "/"; 
    } else { 
     print "$link doesnt contains $substr\n"; 
     $op = "\\"; 
    } 
    push @linkpaths, $path . $op; 
} 

print "\nlinkpaths:\n"; 
foreach (@linkpaths) { 
    print "$_\n"; 
} 

Желаемая Выход:

Path is abc/cde/efg 
abc/cde/efg contains/
Path is \hij\klm\nop 
hij\klm\nop doesnt contain/

linkpaths: 
abc/cde/efg/ 
hij\klm\nop\ 
+2

Вы всегда должны проверить на матч, прежде чем использовать переменные захвата 'если ($ ссылка = ~ т { } g) {...} ' – sln

ответ

2

Проблема не в том, что специальные символы в ваших строках - как простые строки и регулярные выражения - не спасся, и у вас нет use warnings в верхней части программы, которая бы предупредил вас об этом.

Например, если добавить use warnings и использовать Data::Dump для отображения @links массива я получаю этот

Unrecognized escape \h passed through at E:\Perl\source\dd.pl line 8. 
Unrecognized escape \k passed through at E:\Perl\source\dd.pl line 8. 
[ 
    "incl -s projectA /. /abc/cde/efg", 
    "incl -s projectA . hijklm\nop", 
] 

Таким образом, некоторые из слеша второго элемента исчезли.

Теперь регулярное выражение выглядит отлично на лице, но я надеюсь, что это ясно, что ваше Чередование распространяется на всю длину образца, так

m{incl -s projectA /. /|\\.\\(.+)} 

спички либо

incl -s projectA /./

или

\\.\\(.+) 

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

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

m{incl -s projectA ((?:/\. /|\\\. \\).+)} 

, который, используя модификатор /x и заменяя буквенные пространства с \s+, я надеюсь, вы согласитесь, может быть более четко написано

m{ incl \s+ -s \s+ projectA \s+ ((?: /\. \s+/| \\\. \s+ \\) .+) }x 

Вот исправленная версия кода, который включает в себя все изменения, которые я описал.

use strict; 
use warnings; 

my @links = (
    'incl -s projectA /. /abc/cde/efg', 
    'incl -s projectA \. \hij\klm\nop', 
); 

my ($path, $link, @linkpaths, $op); 
my $substr = "/"; 

for my $link (@links) { 

    $link =~ m{incl \s+ -s \s+ projectA \s+ ((?: /\. \s+/| \\\. \s+ \\) .+)}x; 
    $path = $1; 
    print "Path is $path \n"; 
    if (index($path, $substr) >= 0) { 
     print "$link contains $substr\n"; 
     $op = "/"; 
    } 
    else { 
     print "$link doesn't contain $substr\n"; 
     $op = "\\"; 
    } 
    push @linkpaths, "$path$op"; 
} 


print "\n"; 
print "linkpaths:\n"; 
print "$_\n" for @linkpaths; 

выход

Path is /. /abc/cde/efg 
incl -s projectA /. /abc/cde/efg contains/
Path is \. \hij\klm\nop 
incl -s projectA \. \hij\klm\nop doesn't contain/

linkpaths: 
/. /abc/cde/efg/ 
\. \hij\klm\nop\ 

Update

Чтобы захватить только последний путь в каждом элементе списка ввода, который начинается с косой черты или обратной косой черты, Я бы заменил конец рисунка на этот (?: /\. \s+ | \\\. \s+) (.+). Но я считаю, что использовать символ-символ для представления либо прямой, либо обратной косой черты, например, [/\\].

Это еще одно изменение в вашей полной программе

use strict; 
use warnings; 

my @links =(
    'incl -s projectA /. /abc/cde/efg', 
    'incl -s projectA \. \hij\klm\nop', 
); 

my @linkpaths; 
my $substr = '/'; 

for (@links) { 

next unless my ($path) = m{ incl \s+ -s \s+ projectA \s+ [/\\]\. \s+ ([/\\].+) }x; 

print "Path is $path\n"; 

my $op; 
if ($path =~ /\Q$substr/) { 
    printf "%s contains %s\n", $_, $substr; 
    $op = '/'; 
} 
else { 
    printf "%s doesn't contain %s\n", $_, $substr; 
    $op = '\\'; 
} 

push @linkpaths, "$path$op"; 
} 


print "\n"; 
print "linkpaths:\n"; 
print "$_\n" for @linkpaths; 

выход

Path is /abc/cde/efg 
incl -s projectA /. /abc/cde/efg contains/
Path is \hij\klm\nop 
incl -s projectA \. \hij\klm\nop doesn't contain/

linkpaths: 
/abc/cde/efg/ 
\hij\klm\nop\ 
+0

Как я могу заставить мое регулярное выражение сделать мой vaue в пути как' abc/cde/efg/', а не' /./А/CDE/efg'. Пожалуйста, проверьте мой желаемый результат – Jill448

+0

@ sravs448: Я добавил к своему решению, чтобы объяснить – Borodin

0

Возможно хотите регулярное выражение, как этот

# m{incl[ ]-s[ ]projectA(?|[ ]/\.[ ](/)|[ ]\\\.[ ](\\))((?:(?!\1$).)+)$}g 

incl [ ] -s [ ] projectA 
(?| 
     [ ] /\. [ ] 
     (/)       # (1) 
    | [ ] \\\. [ ] 
     (\\)      # (1) 
) 
(       # (2 start) 
     (?: 
      (?! \1 $) 
      . 
    )+ 
)        # (2 end) 
$ 

Образец:

use strict; 
use warnings; 

my @links =(
     'incl -s projectA /. /abc/cde/efg', 
     'incl -s projectA \. \hij\klm\nop' 
     ); 

my ($path,$link,@linkpaths,$op); 
my $substr="/"; 

for (@links) { 
    if (m{incl[ ]-s[ ]projectA(?|[ ]/\.[ ](/)|[ ]\\\.[ ](\\))((?:(?!\1$).)+)$}g) 
    { 
     ($op, $path) = ($1,$2); 
     print "Path is $path \n"; 
     if ($op eq '/') { 
      print "$path contains /\n"; 
     } 
     else { 
      print "$path doesnt contain /\n"; 
     } 
     push @linkpaths, $path . $op; 
    } 
} 
print "\nlinkpaths:\n"; 
for (@linkpaths) { 
    print "$_\n"; 
} 

Выход:

Path is abc/cde/efg 
abc/cde/efg contains/
Path is hij\klm\nop 
hij\klm\nop doesnt contain/

linkpaths: 
abc/cde/efg/ 
hij\klm\nop\