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

时间:2019-08-09 19:58:31

标签: 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

1 个答案:

答案 0 :(得分: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;
}

当前代码错误地假设环境变量的值在路径中仅出现一次。需要对此进行更正,但我们暂时将其搁置一旁。

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

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

%HOMEDRIVE%%HOMEPATH%\AppData\Local\Folder

代替:

%LOCALAPPDATA%\Folder

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

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;
}

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

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