【问题标题】:Shorten path string function [duplicate]缩短路径字符串函数[重复]
【发布时间】:2017-06-12 23:33:22
【问题描述】:

我很好奇是否有以前编写的用于缩短 c 字符串中的文件路径的函数。

例子:

char* filePath1 = "\\folder1\\..\\folder1\\file.dat";
char* filePath2 = "\\folder1\\folder2\\..\\..\\folder1\\file.dat";
char* filePath3 = "\\folder1\\folder3\\..\\folder2\\..\\folder1\\file.dat";

我想知道是否有一个函数可以识别所有这些字符串并将其简化为

char* allFilePaths = "\\folder1\\file.dat";

我没有寄予厚望,但如果有办法避免重写现有(并希望经过良好测试)代码,我完全赞成!

【问题讨论】:

  • 请注意,\f 是换页符。您可能打算每次都使用\\f
  • 您是要进行文本替换还是需要验证folder2folder3 是否存在?系统会验证名称,但这比纯文本替换涉及更多的工作。很可能有 Microsoft API 函数来完成这项工作。我知道我有代码的 Unix 类似物,包括纯文本替换和验证——尽管验证代码不仅仅检查名称是否存在,它也处理符号链接,这很有趣。 (另请注意,由于给定的字符串都是字符串文字,因此您无法在原地可靠地修改它们。)
  • 我的意思是` \\ ` 谢谢指正!我想进行文本替换,因为我假设所有这些文件夹都存在。您知道那些 Microsoft API 函数可能是什么吗? (我假设我不会处理符号链接,但处理这些会更好)
  • 抱歉,我没有记住 Windows API(Unix 已经够难了,但总体上要记住的就更少了)。你可以像我一样搜索,而且你比我更有动力这样做。我可能会使用site:msdn.microsoft.com 作为谷歌搜索词的一部分。对于其余部分,“干净的文件路径”可能会有所帮助。
  • @JonathanLeffler 感谢您的帮助。在我开始深入研究 Window 的 API 之前,您是否知道它可能使用什么样的名称。我什至不知道用什么词来形容这个过程比“缩短路径”更好,这对我来说并没有带来任何好处。它可能有助于大大缩短我的搜索时间。

标签: c windows filepath c-strings


【解决方案1】:

我查看了我们的源代码并意识到我的评论对实际算法的描述相当不准确。因此,我将提供一个工作示例:

#include <iostream>
#include <string>
#include <vector>

using namespace std;

void strTok(const string &text, char delim, vector<string> &tokens)
{
  for (size_t i = 0, j, n = text.size(); i < n; i = j) {
    while (i < n && text[i] == delim) ++i;
    j = text.find(delim, i);
    if (j > n) j = n;
    tokens.push_back(text.substr(i, j - i));
  }
}

string filePathResolve(string filePath)
{
  // make paths Unix-style
  for (char &c : filePath) if (c == '\\') c = '/';
  // consider UNC paths
  const char *root = "";
  if (filePath.length() >= 2 && filePath.compare(0, 2, "//") == 0) {
    root = "//"; filePath.erase(0, 2);
  }
  // split file path into list
  vector<string> list; strTok(filePath, '/', list);
  // remove all non-functional entries (occurrences of '//' and '/.')
  for (size_t i = list.size(); i--;) {
    if (list[i].empty() || list[i] == ".") list.erase(list.begin() + i);
  }
  for (size_t i = 1; i < list.size(); ++i) {
    if (list[i] == ".." && list[i - 1] != "..") {
      list.erase(list.begin() + i - 1, list.begin() + i + 1);
      i -= 2;
    }
  }
  // rebuilt path from list
  filePath = root;
  if (list.size()) {
    filePath += list.front();
    for (size_t i = 1, n = list.size(); i < n; ++i) {
      (filePath += '/') += list[i];
    }
  }
  // done
  return filePath;
}

int main()
{
  string samples[] = {
    "\\folder1\\..\\folder1\\file.dat",
    "\\folder1\\folder2\\..\\..\\folder1\\file.dat",
    "\\folder1\\folder3\\..\\folder2\\..\\folder1\\file.dat",
    "\\.\\folder1\\..\\folder1\\file.dat",
    "folder1\\..\\folder1\\.\\file.dat"
  };
  for (string path : samples) {
    cout << "original: " << path << endl
      <<    "resolved: " << filePathResolve(path) << endl;
  }
  // done
  return 0;
}

在 Windows 10(64 位)的 VS2013 中测试:

original: \folder1\..\folder1\file.dat
resolved: folder1/file.dat
original: \folder1\folder2\..\..\folder1\file.dat
resolved: folder1/file.dat
original: \folder1\folder3\..\folder2\..\folder1\file.dat
resolved: folder1/folder1/file.dat
original: \.\folder1\..\folder1\file.dat
resolved: folder1/file.dat
original: folder1\..\folder1\.\file.dat
resolved: folder1/file.dat

由于我们的软件是可移植的,我们更喜欢/ 作为目录分隔符。但是,这可以很容易地适应相反的方向,即最初将每个 / 替换为 \\ 并专门使用后者。

恕我直言,最关键的部分是UNC paths。幸运的是,我们的客户似乎更不了解他们。至少,我(多年来)从未收到任何投诉。

重新阅读上面链接的维基百科文章,我意识到还提到了 URL。 此算法未正确处理 URL。

【讨论】:

  • 非常感谢您提供这个!这就是我想象的,如果不存在以前的功能,我将自己实现。但是,@Retired Ninja 已将我指向 _fullpath(),它将返回我想要的绝对路径和相对路径,因此我将使用它。
  • 我在 Retired Ninja 的链接之后也注意到了这一点。这可能是更好的解决方案(让操作系统来做)。我什至考虑在我们的软件中替换我从中派生示例的代码。对于便携式解决方案,我还想提一下SO: Safe cross-platform function to get normalized path
猜你喜欢
  • 2020-05-28
  • 1970-01-01
  • 1970-01-01
  • 2014-07-02
  • 2019-11-07
  • 1970-01-01
  • 1970-01-01
  • 2017-11-11
相关资源
最近更新 更多