Regex для соответствия пути, кроме файла и его родительского каталога - PullRequest
0 голосов
/ 03 июля 2019

Я пытаюсь написать выражение, которое соответствует пути к файлу, но исключает имя файла и его родительский каталог.Это моя тестовая строка:

file/in/some/dir1/file1.txt
file/in/some/dir2/file1.txt
file/in/some/dir2/file2.txt
file/in/some/other/dir/file1.txt

я хочу, чтобы регулярное выражение соответствовало следующему:

file/in/some
file/in/some
file/in/some
file/in/some/other

Я пробовал разные виды негативных прогнозов, но я этого не делалдобиться успеха.Все, что я мог придумать, - это выражение, которое соответствует точной противоположности моего желаемого соответствия: (\w+\/\w+\.\w+).При этом я получаю имя файла и его родительский каталог, но я не знаю, как «инвертировать» результат.

Спасибо.

Ответы [ 5 ]

2 голосов
/ 03 июля 2019

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

m{(.*)/\w+/\w+\.\w+$}

Я также изменилтак, чтобы неперехваченная часть совпадения начиналась с / (в противном случае это дало неправильные результаты), использовала m{} вместо //, чтобы разделить регулярное выражение так, чтобы символы / в регулярном выражениине нужно экранировать (\/ - «синдром наклоняющейся зубочистки») и привязать его к концу строки (чтобы он все равно работал правильно, если одно из имен каталогов содержит .).

Полная реализация теста:

#!/usr/bin/env perl    

use strict;
use warnings;
use 5.010;

my @paths = qw(
  file/in/some/dir1/file1.txt
  file/in/some/dir2/file1.txt
  file/in/some/dir2/file2.txt
  file/in/some/other/dir/file1.txt
);

for my $path (@paths) {
  $path =~ m{(.*)/\w+/\w+\.\w+$};
  say $1;
} 

Вывод:

file/in/some
file/in/some
file/in/some
file/in/some/other
1 голос
/ 03 июля 2019

Имя файла или каталога никогда не может содержать косую черту.Таким образом, последние две части пути: /[^/]+/[^/]+$.

#!/usr/bin/perl
use warnings;
use strict;

use Test::More tests => 4;

my %test = (
    'file/in/some/dir1/file1.txt'      => 'file/in/some',
    'file/in/some/dir2/file1.txt'      => 'file/in/some',
    'file/in/some/dir2/file2.txt'      => 'file/in/some',
    'file/in/some/other/dir/file1.txt' => 'file/in/some/other');

for my $path (keys %test) {
    is match($path), $test{$path}, $path;
}

sub match {
    my ($path) = @_;
    return ($path =~ m{(.*)/[^/]+/[^/]+$})[0]
}
0 голосов
/ 03 июля 2019

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

my $files = "1: file/in/some/dir1/file1.txt
2: file/in/some/dir2/file1.txt
3: file/in/some/dir2/file2.txt
4: file/in/some/other/dir/file1.txt";
my @dirs = $files =~ m{((?:\w+/)+)(?=\w+\/\w+\.\w+)}g;
say for @dirs;

Вывод :

file/in/some/
file/in/some/
file/in/some/
file/in/some/other/
0 голосов
/ 03 июля 2019

Вот способ сделать работу:

use strict;
use warnings;
use feature 'say';

while(<DATA>) {
    chomp;
    s~/[^/]+/[^/]+$~~;
    say;
}

__DATA__
file/in/some/dir1/file1.txt
file/in/some/dir2/file1.txt
file/in/some/dir2/file2.txt
file/in/some/other/dir/file1.txt

Выход:

file/in/some
file/in/some
file/in/some
file/in/some/other
0 голосов
/ 03 июля 2019

Попробуйте этот шаблон:

(.*)/\w+\/\w+\.\w+

и затем захватите 1-ю группу.

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