2010-12-13 23 views

risposta

126

Per estrarre un nome di file senza estensione, usare boost :: filesystem :: :: percorso staminali invece di brutto std :: string :: find_last_of (".")

boost::filesystem::path p("c:/dir/dir/file.ext"); 
std::cout << "filename and extension : " << p.filename() << std::endl; // file.ext 
std::cout << "filename only   : " << p.stem() << std::endl;  // file 
+0

concordato. Risponde alla domanda in modo sintetico. – AndyUK

+7

In realtà, p.filename() è di tipo path e sarà racchiuso tra virgolette quando convertito in modo implicito, quindi otterrete: nome file ed estensione: "file.ext" Si può desiderare p.filename(). stringa() invece. –

+1

Con C++ 14/C++ 17 puoi usare 'std :: experimental :: filesystem' risp' std :: filesystem'. Guarda il post di Yuchen Zhong in basso. –

3

non il codice, ma qui è l'idea:

  1. Leggi una std::string dal flusso di input (std::ifstream), ogni lettura esempio sarà il percorso completo
  2. fare un find_last_of sulla corda per il \
  3. Estrarre una stringa da questa posizione fino alla fine, questo ora vi darà il nome del file
  4. fare un find_last_of per ., e entrambi i lati sottostringa darti il ​​nome + l'estensione.
+0

+1 per fornire l'aiuto senza fornire semplicemente il codice. – razlebe

+0

E -1 per essere non portatili :) – Kos

+0

Perché il voto negativo? Se c'è qualcosa di sbagliato in quello che ho detto, fammi sapere e io aggiusterò! – Nim

19

Se volete un modo sicuro (vale a dire portabile tra piattaforme e non mettere le ipotesi sul percorso), mi consiglia di utilizzare boost::filesystem.

Sembrerebbe in qualche modo simile a questo:

boost::filesystem::path my_path(filename); 

Quindi è possibile estrarre i vari dati da questo percorso. Here's the documentation of path object.


BTW: ricordare inoltre che, al fine di utilizzare il percorso come

c:\foto\foto2003\shadow.gif 

è necessario sfuggire alla \ in una stringa letterale:

const char* filename = "c:\\foto\\foto2003\\shadow.gif"; 

Oppure utilizzare / invece:

const char* filename = "c:/foto/foto2003/shadow.gif"; 

Questo si applica solo alla specifica di stringhe letterali nelle virgolette "", il problema non esiste quando si caricano percorsi da un file.

+2

+1 Definately la strada da percorrere.L'esempio sul sito principale offre un modo per cercare una directory: utilizzare il metodo path.extension() per cercare i registri (consultare http://www.boost.org/doc/libs/1_36_0/libs/filesystem/doc/index .htm) – Tom

+0

In effetti questo è nella maggior parte dei casi la strada da percorrere, tuttavia comporta l'aggiunta in alcuni casi di una dipendenza indesiderata su una libreria esterna. Se vuoi lavorare solo ciò che fornisce lo standard C++, ti suggerisco di guardare la regex del C++, dove puoi definire un'espressione regolare per fare ciò che vuoi (molti esempi su internet). Il vantaggio - nessun sovraccarico dovuto ad alcune dipendenze aggiuntive. Tuttavia, anche questa domanda lascia aperta una domanda: è richiesta una formattazione multipla? Boost si prende cura dello stile del percorso, non importa se stai usando Windows o Linux. Usando espressioni regolari devi farlo da solo. – rbaleksandar

13

Dovrai leggere i nomi dei file dal file in std::string. È possibile utilizzare l'operatore di estrazione stringa di std::ostream. Una volta ottenuto il nome file in uno std::string, è possibile utilizzare il metodo std::string::find_last_of per trovare l'ultimo separatore.

Qualcosa di simile a questo:

std::ifstream input("file.log"); 
while (input) 
{ 
    std::string path; 
    input >> path; 

    size_t sep = path.find_last_of("\\/"); 
    if (sep != std::string::npos) 
     path = path.substr(sep + 1, path.size() - sep - 1); 

    size_t dot = path.find_last_of("."); 
    if (dot != std::string::npos) 
    { 
     std::string name = path.substr(0, dot); 
     std::string ext = path.substr(dot, path.size() - dot); 
    } 
    else 
    { 
     std::string name = path; 
     std::string ext = ""; 
    } 
} 
+0

Non voglio essere intelligente, ma dovrebbe essere path.substr e non path.substring, giusto? –

0

Io uso anche questo frammento di determinare il carattere barra appropriata:.

boost::filesystem::path slash("/"); 
    boost::filesystem::path::string_type preferredSlash = slash.make_preferred().native(); 

e quindi sostituire i tagli con la barra preferito per il sistema operativo Utile se si è costantemente la distribuzione tra Linux/. finestre

6

Per C++ 17:

#include <filesystem> 

std::filesystem::path p("c:/dir/dir/file.ext"); 
std::cout << "filename and extension: " << p.filename() << std::endl; // "file.ext" 
std::cout << "filename only: " << p.stem() << std::endl;    // "file" 

Riferimento merito file system: http://en.cppreference.com/w/cpp/filesystem


Come suggerisce @RoiDanto, per la formattazione di uscita, std::out può circondare l'uscita di citazioni, per esempio:

filename and extension: "file.ext" 

È possibile convertire std::filesystem::path-std::string da p.filename().string() se questo è quello che vi serve, per es .:

filename and extension: file.ext 
+0

Ehi @RoiDanton, grazie per la modifica! Ho appena controllato di nuovo il codice di esempio nel link di riferimento, non sembra che sia necessario convertire il tipo di ritorno da 'std :: filesystem :: path' a' std :: string' per poter usare 'std :: cout'. http://en.cppreference.com/w/cpp/filesystem/path/filename Ma se pensi diversamente, sentiti libero di commentare o modificare di nuovo il post. –

+0

Questo è vero, 'std :: cout' può fare affidamento sulla conversione implicita. Tuttavia, poiché i commenti dopo 'std :: cout' dicono file.ext e file,' .string() 'deve essere aggiunto ai commenti o dovrebbero essere" file.ext "e" file ". Con Visual C++ non c'è davvero alcuna differenza (anche senza 'string()' l'output è senza virgolette), ma con gcc 6.1 l'output è con virgolette se '.string()' è omesso. Vedi http://coliru.stacked-crooked.com/view?id=a55ea60bbd36a8a3 –

+0

@RoiDanton, hey, è un'interpretazione interessante. Aggiornerò di nuovo il post Grazie per aver condiviso questo! –

0

Per le macchine Linux o UNIX, il sistema operativo ha due funzioni che si occupano di nomi di percorso e di file. utilizzare man basename per ulteriori informazioni su queste funzioni. Il vantaggio di utilizzare la funzionalità fornita dal sistema è che non è necessario installare boost o la necessità di scrivere le proprie funzioni.

#include <libgen.h> 
     char *dirname(char *path); 
     char *basename(char *path); 

codice di esempio dalla pagina man:

char *dirc, *basec, *bname, *dname; 
      char *path = "/etc/passwd"; 

      dirc = strdup(path); 
      basec = strdup(path); 
      dname = dirname(dirc); 
      bname = basename(basec); 
      printf("dirname=%s, basename=%s\n", dname, bname); 

causa del tipo di argomento non const della funzione basename(), è il codice un po 'non semplice utilizzando questo all'interno C++ . Ecco un semplice esempio dal mio codice base:

string getFileStem(const string& filePath) const { 
    char* buff = new char[filePath.size()+1]; 
    strcpy(buff, filePath.c_str()); 
    string tmp = string(basename(buff)); 
    string::size_type i = tmp.rfind('.'); 
    if (i != string::npos) { 
     tmp = tmp.substr(0,i); 
    } 
    delete[] buff; 
    return tmp; 
} 

L'uso di nuovo/eliminazione non è buono. Avrei potuto metterlo in un blocco try/catch nel caso in cui qualcosa fosse successo tra le due chiamate.

Problemi correlati