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

egmofgnx  于 2023-03-25  发布在  其他
关注(0)|答案(9)|浏览(152)

扩展的最佳方式是什么

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

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

我看到wxWidgets有一个wxExpandEnvVars函数。在这种情况下我不能使用wxWidgets,所以我希望找到一个boost::filesystem等效或类似的。我只是使用home目录作为示例,我正在寻找通用路径扩展。

hts6caw3

hts6caw31#

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

看起来它甚至会做类似于global的扩展(这可能对你的特定情况有用,也可能没用)。

fgw7neuy

fgw7neuy2#

如果你有幸使用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;
}

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

pokxtpni

pokxtpni3#

在Windows上,你可以使用ExpandEnvironmentStrings。还不确定是否有Unix的等价物。

h79rfbju

h79rfbju4#

简单便携:

#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 char *v = getenv( variable.c_str() );
    if( v != NULL ) value = std::string( v );

    return expand_environment_variables( pre + value + post );
}

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

7xzttuei

7xzttuei5#

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

4sup72z8

4sup72z86#

在C/ C++ 中,下面是我在Unix下解析环境变量的方法。fs_parm指针将包含要扩展的可能环境变量的filespec(或文本)。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] = '\0';/* remove newline            */

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

vjhs03f7

vjhs03f77#

这是我使用的:

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

oknwwptz8#

使用Qt,这对我来说很有效:

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

expand_environment_variables(“$HOME/.myconfigfile”);yields /home/martin/.myconfigfile(它也可以使用嵌套的扩展)

sbtkgmzw

sbtkgmzw9#

我需要解析嵌套的env变量的能力,同时保留那些在环境中找不到的变量,以便另一个解析器处理,所以我基于@sfkleach的优秀答案提出了这个问题:

#include <string>
#include <regex>

// Update the input string.
void autoExpandEnvironmentVariables(std::string& text) {
    using namespace std;
    static regex envRegex("\\$\\{?(\\w+)\\}?", regex::ECMAScript);

    // 0,1 indicates to get the full match + first subgroup
    const string matchText = text;
    sregex_token_iterator matchIter(matchText.begin(), matchText.end(), envRegex, {0, 1});
    for (sregex_token_iterator end; matchIter != end; ++matchIter) {
        const string match = matchIter->str();
        const string envVarName = (++matchIter)->str();

        // Search for env var and replace if found
        const char * s = getenv(envVarName.c_str());
        if (s != nullptr) {
            string value(s);

            // Handle nested env vars
            autoExpandEnvironmentVariables(value);
            
            // Since we're manipulating the string, do a new find
            // instead of using original match info
            size_t pos = text.find(match);
            if (pos != string::npos) {
                text.replace(pos, match.length(), value);
            }
        }
    }
}

相关问题