Как я могу удалить буквы диска Windows из моего измененного пути?Дельфи или Паскаль - PullRequest
2 голосов
/ 26 февраля 2012

В дополнение к на этот ответ У меня есть еще одна проблема. Я пишу Free Pascal, но решения Delphi, вероятно, будут работать.

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

C: \ SourceDir \ SubDirA становится F: \ DestinationDir \ SourceDir \ SubDirA.

Однако, решение, которое я имею для версии моей программы для Linux (как опубликовано в ссылке выше), не совсем работает с версией Windows, потому что я в итоге:

F: \ DestionationDir. \ C: SourceDir \ SubDirA

, что недействительно.

Итак, я придумал этот код «только для запуска в Windows», чтобы удалить центральную букву преобразованного пути, но оставил начальную букву в начале, сказав: «Посмотрите на строку, начиная с 4-го символа слева Если вы найдете «C:», удалите его «, чтобы путь стал F: \ DestinationDir \ SourceDir \ SubDirA.

{$IFDEF Windows} // Only do this for the Windows version
    k := posex('C:', FinalisedDestDir, 4);  // Find 'C:' in the middle of the concatanated path and return its position as k
    Delete(FinalisedDestDir, k, 2);  // Delete the 2 chars 'C:' of 'C:\' if found, leaving the '\' to keep the path valid
{$ENDIF}   

Теперь это работает нормально, если C: является источником выбранного каталога. Но очевидно, что если пользователь копирует данные с другого диска (например, E :, F :, G: или любого другого диска до Z :), он не будет работать.

Итак, мой вопрос: как мне закодировать его так, чтобы оно гласило: «Если после 4-го символа слева будет найдена буква диска a: to z:, удалите ее»? Хотя любое решение, которое работает, «подойдет», в идеале мне нужно быстрое решение. Лучшее решение было бы, во-первых, не иметь его там, но, учитывая решение, которое я разместил в ответ на мое предыдущее сообщение, я не могу понять, как его не использовать из-за процедуры, которую я использую для формирования Это.

Ответы [ 5 ]

6 голосов
/ 26 февраля 2012

Вот код, который я использую в своем приложении:

function CombinePath(const BaseDir, Path: string): string;
begin
  if IsPathDelimiter(Path, 1) then
    Result := ExcludeTrailingBackSlash(BaseDir) + Path else
    Result := IncludeTrailingBackSlash(BaseDir) + Path;
end;

function MapRootPath(const Path, NewPath: string): string;
var
  Drive, RelativePath: string;
begin
  Drive := ExtractFileDrive(Path); // e.g: "C:"
  RelativePath := ExtractRelativePath(Drive, Path); // e.g: "Program Files\MyApp"
  Result := CombinePath(NewPath, RelativePath);
end;

Использование:

ShowMessage(MapRootPath('C:\SourceDir\SubDirA', 'F:\DestionationDir'));
// result is "F:\DestionationDir\SourceDir\SubDirA"
3 голосов
/ 26 февраля 2012

Я предлагаю вам два решения:

Нормализуйте ваши пути перед объединением папок

Вы знаете поговорку: профилактика всегда лучше лечения.Почему бы вам не "нормализовать" пути до , когда вы делаете свои конкатенации?Это дает вам возможность:

  • Удалить букву диска из пути, если имя начинается с пути.Если второй символ в строке - :, а третий - \, вы знаете, что это путь Windows, содержащий букву диска.Вы можете удалить все первые 3 символа.
  • Имея дело с именами UNC, вы не упомянули их: \\ComputerName\ShareName\SubFolder
  • Исправьте косые черты, чтобы они соответствовали вашей текущей платформе

Удалите букву диска позже

Это некрасиво (потому что вы не должны в первую очередь попадать в эту ситуацию), но вы всегда можете искать :\ - не C:,: недопустимо в именах папок или файлов в Windows, поэтому, если вы найдете его, вы знаете, что ему предшествует ровно один символ, и это буква DRIVE.Получить индекс для :\, вычесть `, удалить 2 символа из этого индекса.

1 голос
/ 26 февраля 2012

Я не знаю freepascal, но для этой проблемы используйте регулярное выражение, такое как [A-Za-z] \:, чтобы найти такую ​​строку. Я вижу из вики Freepascal, что он поддерживает регулярные выражения http://wiki.freepascal.org/Regexpr.

0 голосов
/ 26 февраля 2012

Спасибо за всю помощь с этим.Отдельное спасибо kobik, чей пример кода очень понятен и за ним легко следовать.Это, конечно, один из способов сделать это, но пока я ждал ответов, я придумал следующее, что также, кажется, работает очень хорошо для меня:

type
TRange = 'A'..'Z';
...

{$IFDEF Windows}
    // Due to the nonsenseories of Windows, we have to allow for driver lettering.

  for DriveLetter in TRange do
      begin
        k := posex(DriveLetter+':', FinalisedDestDir, 4);  // Find e.g 'C:' in the middle of the concatanated path and return its position, leaving the first 'C:\' at the start in place
        Delete(FinalisedDestDir, k, 2);  // Delete 'C:' of 'C:\' if found, leaving the '\'
      end;
{$ENDIF}
0 голосов
/ 26 февраля 2012

Вы также можете посмотреть, могут ли помочь некоторые функции SysUtils, в том числе:

  • ExpandFileName ()

  • IncludeTrailingSlashes ()

  • и т.д ..

Перевод вашего пути в «нормализованную» форму - как эти функции могли бы сделать для вас - делает тривиальным преобразование между соглашениями о путях Linux и Windows.

Просто мысль ...

...