2009-12-14 7 views
18

Qual è il modo migliore per espandereespandere i nomi dei file che hanno le variabili di ambiente nel loro percorso

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

o

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

con fuori che attraversa la stringa di percorso alla ricerca di variabili environement direttamente? Vedo che wxWidgets ha una funzione wxExpandEnvVars. Non posso usare wxWidgets in questo caso, quindi speravo di trovare un boost :: equivalente al filesystem o simile. Sto solo usando la home directory come esempio, sto cercando l'espansione del percorso generale.

risposta

16

Su Windows, è possibile utilizzare ExpandEnvironmentStrings. Non sono ancora sicuro di un equivalente Unix.

+0

Grazie Rob. Questo mi porta a metà strada lì. Immagino che esaminerò il metodo di analisi per i casi non Windows. – Dan

19

Per UNIX (o almeno POSIX) sistemi, uno sguardo alla 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; 
} 

Sembra che sarà anche fare espansioni glob-simili (che può o non può essere utile per la vostra situazione particolare) .

+0

Per me, questa è l'altra metà. Questa soluzione con quella sopra funziona sia su Posix che su Window. – xryl669

+1

Se lo potessi farei tre volte più volte. Ottima risposta usando le strutture fornite dal sistema che sono certamente meno inclini agli errori delle cose di regex. –

3

All'interno del linguaggio C/C++, ecco cosa faccio per risolvere le variabili ambientali in Unix. Il puntatore fs_parm conterrebbe il filespec (o il testo) delle possibili variabili ambientali da espandere. Lo spazio su cui wrkSpc punta deve essere MAX_PATH + 60 caratteri. Le doppie virgolette nella stringa echo servono a impedire l'elaborazione dei caratteri jolly. La maggior parte delle shell di default dovrebbe essere in grado di gestirle.


    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   */ 

Per MS Windows, utilizzare la funzione ExpandEnvironmentStrings().

1

Questo è quello che uso:

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

Poiché la questione è aggiunto "wxWidgets", è possibile utilizzare wxExpandEnvVars() funzione utilizzata da wxConfig per il suo ambiente di espansione variabile. La funzione in sé non è purtroppo documentata, ma fondamentalmente fa ciò che si pensa che dovrebbe e espande qualsiasi occorrenza di $VAR, $(VAR) o ${VAR} su tutte le piattaforme e anche di %VAR% solo in Windows.

-1

Poiché la domanda è codificata in C++, è possibile utilizzare lo standard getenv, con un tocco di standard C++ 11 regex per sostituire la variabile con il suo valore.

6

semplice e portatile:

#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"); cede /home/joe/.myconfigfile

+0

Si noti che questo espande solo una singola variabile di ambiente. Quale è OK per l'esempio. Se è necessario espandere più variabili di ambiente in una stringa, chiama expane_environment_variables in modo ricorsivo sul post. – tbleher

+1

Nota: si chiama 'getenv (variable.c_str())' due volte per ottenere la stessa var, meglio per memorizzare il risultato. – vladon

0

Utilizzando Qt, questo funziona per me:

#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 (QString ("$ HOME/.myconfigfile")) ; yields /home/martin/.myconfigfile (Funziona anche con espansioni annidate)

5

Se si ha il lusso di usare C++ 11, le espressioni regolari sono piuttosto utili. Ho scritto una versione per l'aggiornamento sul posto e una versione dichiarativa.

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

Un vantaggio di questo approccio è che può essere adattato facilmente a far fronte a variazioni sintattiche e trattare con ampie stringhe troppo. (Compilato e testato utilizzando Clang su OS X con il flag -std = C++ 0x)

+0

g ++ 4.9.3 (Ubuntu) non può essere compilato, è qualcosa correlato alla conversione tra iteratore e const_iterator. Devo cambiare text.replace (match [0] .first, match [0] .second, var); to text.replace (match.position (0), match.length (0), var); – fchen