Как я могу объединить перекрывающиеся сегменты пути, чтобы получить полный путь в Perl? - PullRequest
2 голосов
/ 15 сентября 2009

Я действительно не люблю Perl, но я должен использовать его для своей текущей задачи.

Вот моя проблема ... У меня есть три строки, которые составляют элементы полного пути к каталогу (Windows, но должен работать и на * nix). Например ...

$root = "c:\\checkout\\omega";
$client = "abc\\mainline";
$build = "omega\\abc\\mainline\\host\\make";

Я хочу объединить их, чтобы получить полный путь, например

"c:\\checkout\\omega\\abc\\mainline\\host\\make" 

Но между строкой $ build и строкой $root и / или $client есть пересечение. Как я могу объединить их, чтобы получить полный путь и игнорировать перекрытие. $client, вероятно, можно игнорировать в этом примере, но есть и другие случаи, когда $build may перекрываются $client, но не $root.

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

Может быть, какая-то строка или операция. Я глупо пытался ...

($root . $client) | $build 

Но это побитовая операция и результат мусорный!

Ответы [ 5 ]

4 голосов
/ 15 сентября 2009

Это регулярное выражение ниже лучше подходит для устранения повторяющихся последовательностей пути.

qr{ ( 
      [\\/]  # 1. starts with a path break
      .+?    # 2. whatever
    )
    \1       # whatever was captured in the previous group 
             # it forces us to backtrack on #2 until we have duplicates
             # it will necessarily have a path break at the beginning
  }x;

Регулярное выражение, предоставленное Дейвом Уэббом, работает, пока в пути нет повторяющихся букв . Просто сделайте последний узел 'mmake' и он сломается.

Я получаю:

original c:\checkout\omega\abc\mainline\omega\abc\mainline\host\mmake
overlap m
new c:\checkout\omega\abc\mainline\omega\abc\mainline\host\make

Вы хотите, чтобы повторение было именами каталогов , а не символами.

Также все, что нужно, - это простая замена. Скорее всего, когда вы видите ^.* или .*$ в регулярном выражении, это не нужно. И в этом больше нет необходимости.

На самом деле все это можно сделать с помощью:

$path =~ s/([\\\/]+.+?)\1/$1/;

Заменить что-нибудь, и это дублирует что-то.

File::Spec

Кстати, File::Spec - это общепринятый способ объединения каталогов независимо от платформы:

my $path = File::Spec->catfile( $root, $client, $build );
$path =~ s/([\\\/]+.+?)\1/$1/;

У меня есть небольшая любимая мозоль с File::Spec. Мне нравится , используя / для каталогов. И Perl работает с / в среде Windows. Пока я нахожусь в пределах Perl, мне никогда не придется разделять пути с помощью символа escape (в семействе языков C). File::Spec заставляет обратную косую черту соответствовать платформе Windows.

Однако, если это то, что вы ищете, это, вероятно, больше причин для его использования.

3 голосов
/ 15 сентября 2009

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

Например:

$root = "c:\\checkout\\omega";
$build = "omega\\abc\\mainline\\host\\make";    

# Concatenate Strings
$path = "$root\\$build";
print "original ",$path,"\n";

# Look for overlap using a backreference
$path =~ /^.*(.+)\1.*$/;
print "overlap ",$1,"\n";

# Do a substitution to remove the overlap
$path =~ s/^(.*)(.+)\2(.*)$/\1\2\3/;
print "new ",$path,"\n";

Это даст следующий вывод:

original c:\checkout\omega\omega\abc\mainline\host\make
overlap omega\
new c:\checkout\omega\abc\mainline\host\make
1 голос
/ 15 сентября 2009

Вот один из способов сделать это:

  1. используйте одинарные кавычки для сохранения обратной косой черты (если вы хотите использовать обратную косую черту);

  2. my $ fullpath = join "", $ root, $ client, $ build;

join - это «клей» между строками - в данном случае, пустой или ничего.

Вышесказанное дает:

c:\checkout\omegaabc\mainlineomega\abc\mainline\host\make

, поэтому, если вам нужны обратные слеши между строками, используйте join "\\", что даст:

c:\checkout\omega\abc\mainline\omega\abc\mainline\host\make

Со строками в двойных кавычках символ после \ будет экранирован. В одинарных кавычках литеральная строка сохраняется.

Тогда вы можете легко конвертировать обратные слэши в (* nix) прямые слэши, но это другой процесс. В Perl всегда use strict;, который всегда будет указывать на возможные сбои при запуске из командной строки.

0 голосов
/ 15 сентября 2009

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

Yepp. Посмотрите на модуль Path :: Class . Из вашего вопроса не совсем понятно, что вы пытаетесь сделать, но Class::Path позволяет вам управлять путями кроссплатформенным способом.

0 голосов
/ 15 сентября 2009

Не зная, есть ли какие-либо правила для вашей структуры (например, $ client кажется излишним в вашем примере?), Но если есть, то вы можете делать такие вещи:

my $root  = 'c:\checkout\omega'; 
my $build = 'omega\abc\mainline\host\make';

# $root + $build minus first node
my $file = join '\\', $root, ( split /\\/, $build, 2 )[1];
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...