将完整路径转换为带有环境变量的路径

nls*_*k01 5 c#

我想使用C#将完整路径转换为环境变量路径

这有可能吗?

C:\Users\Username\Documents\Text.txt -> %USERPROFILE%\Documents\Text.txt
C:\Windows\System32\cmd.exe -> %WINDIR%\System32\cmd.exe
C:\Program Files\Program\Program.exe -> %PROGRAMFILES%\Program\Program.exe
Run Code Online (Sandbox Code Playgroud)

Rot*_*tem 5

通过遍历所有环境变量并检查字符串中包含哪个变量的值,然后将字符串的该部分替换为由包围的相应变量名称,是可能的%

首次尝试:

string Tokenify(string path)
{
    foreach (DictionaryEntry e in Environment.GetEnvironmentVariables())
    {
        int index = path.IndexOf(e.Value.ToString());
        if (index > -1)
        {
            //we need to make sure we're not already inside a tokenized part.
            int numDelimiters = path.Take(index).Count(c => c == '%');
            if (numDelimiters % 2 == 0)
            {
                path = path.Replace(e.Value.ToString(), $"%{e.Key.ToString()}%");
            }
        }
    }
    return path;
}
Run Code Online (Sandbox Code Playgroud)

该代码当前错误地假设环境变量的值在路径中仅出现一次。这需要纠正,但是现在让我们将其放在一边。

另请注意,并非所有环境变量都代表目录。例如,如果我在字符串上运行此方法,则会"6"得到"%PROCESSOR_LEVEL%"。可以通过Directory.Exists()在使用之前检查环境变量值来补救此问题。这可能还会使检查我们是否已经在字符串的标记化部分中的需求无效。

您可能还想按长度对环境变量进行排序,以便始终使用最具体的变量。否则,您可能会得到:

%HOMEDRIVE%%HOMEPATH%\AppData\Local\Folder
Run Code Online (Sandbox Code Playgroud)

代替:

%LOCALAPPDATA%\Folder
Run Code Online (Sandbox Code Playgroud)

更新了首选最长变量的代码:

string Tokenify(string path)
{
    //first find all the environment variables that represent paths.
    var validEnvVars = new List<KeyValuePair<string, string>>();
    foreach (DictionaryEntry e in Environment.GetEnvironmentVariables())
    {       
        string envPath = e.Value.ToString();
        if (System.IO.Directory.Exists(envPath))
        {
            //this would be the place to add any other filters.
            validEnvVars.Add(new KeyValuePair<string, string>(e.Key.ToString(), envPath));
        }
    }

    //sort them by length so we always get the most specific one.
    //if you are dealing with a large number of strings then orderedVars can be generated just once and cached.
    var orderedVars = validEnvVars.OrderByDescending(kv => kv.Value.Length);

    foreach (var kv in orderedVars)
    {
        //using regex just for case insensitivity. Otherwise just use string.Replace.
        path = Regex.Replace(path, Regex.Escape(kv.Value), $"%{kv.Key}%", RegexOptions.IgnoreCase);
    }
    return path;
}
Run Code Online (Sandbox Code Playgroud)

您可能仍想添加检查,以避免对字符串的各个部分进行双令牌处理,但这在此版本中不太可能成为问题。

另外,您可能希望过滤掉一些变量,例如驱动器根,例如(%HOMEDRIVE%)或其他任何条件。