C++ 展开路径中包含环境变量的文件名

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1902681/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 21:32:18  来源:igfitidea点击:

expand file names that have environment variables in their path

c++wxwidgetsboost-filesystem

提问by Dan

What's the best way to expand

什么是最好的扩展方式

${MyPath}/filename.txt to /home/user/filename.txt

or

或者

%MyPath%/filename.txt to c:\Documents and settings\user\filename.txt

with out traversing the path string looking for environement variables directly? I see that wxWidgets has a wxExpandEnvVarsfunction. I can't use wxWidgets in this case, so I was hoping to find a boost::filesystem equivalent or similar. I am only using the home directory as an example, I am looking for general purpose path expansion.

无需遍历路径字符串直接查找环境变量?我看到 wxWidgets 有一个wxExpandEnvVars函数。在这种情况下我不能使用 wxWidgets,所以我希望找到一个 boost::filesystem 等效或类似的。我仅以主目录为例,我正在寻找通用路径扩展。

回答by MikeGM

For UNIX (or at least POSIX) systems, have a look at wordexp:

对于 UNIX(或至少 POSIX)系统,请查看wordexp

#include <iostream>
#include <wordexp.h>
using namespace std;
int main() {
  wordexp_t p;
  char** w;
  wordexp( "$HOME/bin", &p, 0 );
  w = p.we_wordv;
  for (size_t i=0; i<p.we_wordc;i++ ) cout << w[i] << endl;
  wordfree( &p );
  return 0;
}

It seems it will even do glob-like expansions (which may or may not be useful for your particular situation).

似乎它甚至会进行类似 glob 的扩展(这可能对您的特定情况有用也可能没有用)。

回答by Rob Kennedy

On Windows, you can use ExpandEnvironmentStrings. Not sure about a Unix equivalent yet.

在 Windows 上,您可以使用ExpandEnvironmentStrings. 还不确定 Unix 等价物。

回答by sfkleach

If you have the luxury of using C++11, then regular expressions are quite handy. I wrote a version for updating in place and a declarative version.

如果您有幸使用 C++11,那么正则表达式非常方便。我编写了一个用于就地更新的版本和一个声明性版本。

#include <string>
#include <regex>

// Update the input string.
void autoExpandEnvironmentVariables( std::string & text ) {
    static std::regex env( "\$\{([^}]+)\}" );
    std::smatch match;
    while ( std::regex_search( text, match, env ) ) {
        const char * s = getenv( match[1].str().c_str() );
        const std::string var( s == NULL ? "" : s );
        text.replace( match[0].first, match[0].second, var );
    }
}

// Leave input alone and return new string.
std::string expandEnvironmentVariables( const std::string & input ) {
    std::string text = input;
    autoExpandEnvironmentVariables( text );
    return text;
}

An advantage of this approach is that it can be adapted easily to cope with syntactic variations and deal with wide strings too. (Compiled and tested using Clang on OS X with the flag -std=c++0x)

这种方法的一个优点是它可以很容易地适应句法变化并处理宽字符串。(在 OS X 上使用 Clang 编译和测试,标志为 -std=c++0x)

回答by user3116736

Simple and portable:

简单便携:

#include <cstdlib>
#include <string>

static std::string expand_environment_variables( const std::string &s ) {
    if( s.find( "${" ) == std::string::npos ) return s;

    std::string pre  = s.substr( 0, s.find( "${" ) );
    std::string post = s.substr( s.find( "${" ) + 2 );

    if( post.find( '}' ) == std::string::npos ) return s;

    std::string variable = post.substr( 0, post.find( '}' ) );
    std::string value    = "";

    post = post.substr( post.find( '}' ) + 1 );

    const *v = getenv( variable.c_str() );
    if( v != NULL ) value = std::string( v );

    return expand_environment_variables( pre + value + post );
}

expand_environment_variables( "${HOME}/.myconfigfile" );yields /home/joe/.myconfigfile

expand_environment_variables( "${HOME}/.myconfigfile" );产量 /home/joe/.myconfigfile

回答by Dennis

Within the C/C++ language, here is what I do to resolve environmental variables under Unix. The fs_parm pointer would contain the filespec (or text) of possible environmental variables to be expanded. The space that wrkSpc points to must be MAX_PATH+60 chars long. The double quotes in the echo string are to prevent the wild cards from being processed. Most default shells should be able to handle this.

在 C/C++ 语言中,这是我在 Unix 下解决环境变量的方法。fs_parm 指针将包含要扩展的可能环境变量的文件规范(或文本)。wrkSpc 指向的空间必须是 MAX_PATH+60 个字符长。echo 字符串中的双引号是为了防止处理通配符。大多数默认 shell 应该能够处理这个问题。


   FILE *fp1;

   sprintf(wrkSpc, "echo \"%s\" 2>/dev/null", fs_parm);
   if ((fp1 = popen(wrkSpc, "r")) == NULL || /* do echo cmd     */
       fgets(wrkSpc, MAX_NAME, fp1) == NULL)/* Get echo results */
   {                        /* open/get pipe failed             */
     pclose(fp1);           /* close pipe                       */
     return (P_ERROR);      /* pipe function failed             */
   }
   pclose(fp1);             /* close pipe                       */
   wrkSpc[strlen(wrkSpc)-1] = '
const unsigned short expandEnvVars(std::string& original)
{
    const boost::regex envscan("%([0-9A-Za-z\/]*)%");
    const boost::sregex_iterator end;
    typedef std::list<std::tuple<const std::string,const std::string>> t2StrLst;
    t2StrLst replacements;
    for (boost::sregex_iterator rit(original.begin(), original.end(), envscan); rit != end; ++rit)
        replacements.push_back(std::make_pair((*rit)[0],(*rit)[1]));
    unsigned short cnt = 0;
    for (t2StrLst::const_iterator lit = replacements.begin(); lit != replacements.end(); ++lit)
    {
        const char* expanded = std::getenv(std::get<1>(*lit).c_str());
        if (expanded == NULL)
            continue;
        boost::replace_all(original, std::get<0>(*lit), expanded);
        cnt++;
    }
    return cnt;
}
';/* remove newline */

For MS Windows, use the ExpandEnvironmentStrings() function.

对于 MS Windows,请使用 ExpandEnvironmentStrings() 函数。

回答by Andreas

This is what I use:

这是我使用的:

#include <QString>
#include <QRegExp>

QString expand_environment_variables( QString s )
{
    QString r(s);
    QRegExp env_var("\$([A-Za-z0-9_]+)");
    int i;

    while((i = env_var.indexIn(r)) != -1) {
        QByteArray value(qgetenv(env_var.cap(1).toLatin1().data()));
        if(value.size() > 0) {
            r.remove(i, env_var.matchedLength());
            r.insert(i, value);
        } else
            break;
    }
    return r;
}

回答by VZ.

As the question is tagged "wxWidgets", you can use wxExpandEnvVars()function used by wxConfigfor its environment variable expansion. The function itself is unfortunately not documented but it basically does what you think it should and expands any occurrences of $VAR, $(VAR)or ${VAR}on all platforms and also of %VAR%under Windows only.

由于问题被标记为“wxWidgets”,因此您可以使用wxConfig使用的wxExpandEnvVars()函数进行环境变量扩展。不幸的是,该函数本身没有记录,但它基本上可以做你认为应该做的事情,并扩展,或在所有平台上以及仅在 Windows 下的任何出现。$VAR$(VAR)${VAR}%VAR%

回答by Martin A

Using Qt, this works for me:

使用 Qt,这对我有用:

##代码##

expand_environment_variables(QString("$HOME/.myconfigfile")); yields /home/martin/.myconfigfile (It also works with nested expansions)

expand_environment_variables(QString("$HOME/.myconfigfile")); 产生 /home/martin/.myconfigfile (它也适用于嵌套扩展)