Frage

Gegeben eine Zeichenfolge "filename.conf", wie überprüfe ich den Erweiterungsteil?

Ich brauche eine plattformübergreifende Lösung.

War es hilfreich?

Lösung

Sie müssen darauf achten, Dateinamen mit mehr als einem Punkt zu verwenden.Beispiel: c:\.directoryname\file.name.with.too.many.dots.ext würde von nicht korrekt gehandhabt werden strchr oder find.

Mein Favorit wäre das Boost-Dateisystembibliothek die eine Erweiterungsfunktion (Pfad) haben

Andere Tipps

Ist das eine zu einfache Lösung?

#include <iostream>
#include <string>

int main()
{
  std::string fn = "filename.conf";
  if(fn.substr(fn.find_last_of(".") + 1) == "conf") {
    std::cout << "Yes..." << std::endl;
  } else {
    std::cout << "No..." << std::endl;
  }
}

Der beste Weg besteht darin, keinen Code zu schreiben, der dies tut, sondern vorhandene Methoden aufzurufen.In Windows ist das PathFindExtension Die Methode ist wahrscheinlich die einfachste.

Warum sollten Sie also nicht Ihr eigenes schreiben?

Nehmen wir das strrchr-Beispiel: Was passiert, wenn Sie diese Methode für die folgende Zeichenfolge „c:\Programme\AppleGate.Net eadme“ verwenden?Ist „.Net eadme“ die Erweiterung?Es ist einfach, etwas zu schreiben, das für einige Beispielfälle funktioniert, aber es kann viel schwieriger sein, etwas zu schreiben, das für alle Fälle funktioniert.

Vorausgesetzt, Sie haben Zugriff auf STL:

std::string filename("filename.conf");
std::string::size_type idx;

idx = filename.rfind('.');

if(idx != std::string::npos)
{
    std::string extension = filename.substr(idx+1);
}
else
{
    // No extension found
}

Bearbeiten: Dies ist eine plattformübergreifende Lösung, da Sie die Plattform nicht erwähnt haben.Wenn Sie speziell mit Windows arbeiten, sollten Sie die Windows-spezifischen Funktionen nutzen, die von anderen im Thread erwähnt wurden.

Jemand anderes hat Boost erwähnt, aber ich wollte nur den eigentlichen Code hinzufügen, um dies zu tun:

#include <boost/filesystem.hpp>
using std::string;
string texture         = foo->GetTextureFilename();
string file_extension  = boost::filesystem::extension(texture);
cout << "attempting load texture named " << texture
     << "    whose extensions seems to be " 
     << file_extension << endl;
// Use JPEG or PNG loader function, or report invalid extension

Tatsächlich kann die STL dies ohne viel Code tun. Ich empfehle Ihnen, ein wenig über die STL zu lernen, da Sie damit einige ausgefallene Dinge tun können. Jedenfalls verwende ich diese.

std::string GetFileExtension(const std::string& FileName)
{
    if(FileName.find_last_of(".") != std::string::npos)
        return FileName.substr(FileName.find_last_of(".")+1);
    return "";
}

Diese Lösung gibt immer die Erweiterung zurück, auch bei Zeichenfolgen wie „this.a.b.c.d.e.s.mp3“. Wenn sie die Erweiterung nicht finden kann, wird „“ zurückgegeben.

Eigentlich ist der einfachste Weg

char* ext;
ext = strrchr(filename,'.') 

Eines sollten Sie sich merken:Wenn '.' existiert nicht im Dateinamen, ext wird es sein NULL.

Ich bin heute selbst auf diese Frage gestoßen, obwohl ich bereits einen funktionierenden Code hatte, musste ich feststellen, dass er in manchen Fällen nicht funktionieren würde.

Während einige Leute bereits vorgeschlagen haben, einige externe Bibliotheken zu verwenden, bevorzuge ich es, zu Lernzwecken meinen eigenen Code zu schreiben.

Einige Antworten beinhalteten die Methode, die ich ursprünglich verwendet hatte (nach dem letzten „.“ gesucht), aber ich erinnerte mich, dass versteckte Dateien/Ordner unter Linux mit „.“ beginnen.Wenn die Datei also ausgeblendet ist und keine Erweiterung hat, wird der gesamte Dateiname als Erweiterung verwendet.Um das zu vermeiden, habe ich diesen Code geschrieben:

bool getFileExtension(const char * dir_separator, const std::string & file, std::string & ext)
{
    std::size_t ext_pos = file.rfind(".");
    std::size_t dir_pos = file.rfind(dir_separator);

    if(ext_pos>dir_pos+1)
    {
        ext.append(file.begin()+ext_pos,file.end());
        return true;
    }

    return false;
}

Ich habe das noch nicht vollständig getestet, aber ich denke, dass es funktionieren sollte.

_splitpath, _wsplitpath, _splitpath_s, _wsplitpath_w

Ich denke, das ist nur Windows (Plattform SDK)?

Mit C++17 und seinen std::filesystem::path::extension (die Bibliothek ist der Nachfolger von boost::filesystem) würden Sie Ihre Aussage aussagekräftiger gestalten, als wenn Sie z.B. std::string.

#include <iostream>
#include <filesystem> // C++17
namespace fs = std::filesystem;

int main()
{
    fs::path filePath = "my/path/to/myFile.conf";
    if (filePath.extension() == ".conf") // Heed the dot.
    {
        std::cout << filePath.stem() << " is a valid type."; // Output: "myFile is a valid type."
    }
    else
    {
        std::cout << filePath.filename() << " is an invalid type."; // Output: e.g. "myFile.cfg is an invalid type"
    }
}

Siehe auch std::filesystem::path::stem, std::filesystem::path::filename.

Die Verwendung von std::string's find/rfind löst DIESES Problem, aber wenn Sie viel mit Pfaden arbeiten, sollten Sie sich boost::filesystem::path ansehen, da Ihr Code dadurch viel sauberer wird als das Hantieren mit rohen String-Indizes/Iteratoren.

Ich empfehle Boost, da es sich um eine hochwertige, gut getestete (Open Source und kommerziell) kostenlose und vollständig portable Bibliothek handelt.

Für Zeichenfolgen vom Typ „char“ können Sie Folgendes verwenden:

#include <ctype.h>
#include <string.h>

int main()
{
    char filename[] = "apples.bmp";
    char extension[] = ".jpeg";

    if(compare_extension(filename, extension) == true)
    {
        // .....
    } else {
        // .....
    }

    return 0;
}

bool compare_extension(char *filename, char *extension)
{
    /* Sanity checks */

    if(filename == NULL || extension == NULL)
        return false;

    if(strlen(filename) == 0 || strlen(extension) == 0)
        return false;

    if(strchr(filename, '.') == NULL || strchr(extension, '.') == NULL)
        return false;

    /* Iterate backwards through respective strings and compare each char one at a time */

    for(int i = 0; i < strlen(filename); i++)
    {
        if(tolower(filename[strlen(filename) - i - 1]) == tolower(extension[strlen(extension) - i - 1]))
        {
            if(i == strlen(extension) - 1)
                return true;
        } else
            break;
    }

    return false;
}

Kann neben Dateinamen auch Dateipfade verarbeiten.Funktioniert sowohl mit C als auch C++.Und plattformübergreifend.

Gute Antworten, aber ich sehe, dass die meisten von ihnen einige Probleme haben:Erstens denke ich, dass eine gute Antwort für vollständige Dateinamen mit Pfadüberschriften funktionieren sollte, sie sollte auch für Linux oder Windows funktionieren oder, wie bereits erwähnt, plattformübergreifend sein.Für die meisten Antworten;Bei Dateinamen ohne Erweiterung, aber einem Pfad mit einem Ordnernamen mit Punkt, kann die Funktion nicht die richtige Erweiterung zurückgeben:Beispiele für einige Testfälle könnten wie folgt sein:

    const char filename1 = {"C:\\init.d\\doc"}; // => No extention
    const char filename2 = {"..\\doc"}; //relative path name => No extention
    const char filename3 = {""}; //emputy file name => No extention
    const char filename4 = {"testing"}; //only single name => No extention
    const char filename5 = {"tested/k.doc"}; // normal file name => doc
    const char filename6 = {".."}; // parent folder => No extention
    const char filename7 = {"/"}; // linux root => No extention
    const char filename8 = {"/bin/test.d.config/lx.wize.str"}; // ordinary path! => str

"Brian Newman„Vorschlag schlägt für Dateiname1 und Dateiname4 fehl.und die meisten anderen Antworten, die auf der umgekehrten Suche basieren, schlagen für Dateiname1 fehl.Ich schlage vor, die folgende Methode in Ihre Quelle aufzunehmen:Dabei handelt es sich um eine Funktion, die den Index des ersten Zeichens der Erweiterung oder die Länge der angegebenen Zeichenfolge zurückgibt, wenn sie nicht gefunden wird.

size_t find_ext_idx(const char* fileName)
{
    size_t len = strlen(fileName);
    size_t idx = len-1;
    for(size_t i = 0; *(fileName+i); i++) {
        if (*(fileName+i) == '.') {
            idx = i;
        } else if (*(fileName + i) == '/' || *(fileName + i) == '\\') {
            idx = len - 1;
        }
    }
    return idx+1;
}

Sie könnten den obigen Code wie folgt in Ihrer C++-Anwendung verwenden:

std::string get_file_ext(const char* fileName)
{
    return std::string(fileName).substr(find_ext_idx(fileName));
}

Der letzte Punkt ist, dass in manchen Fällen ein Ordner dem Dateinamen als Argument übergeben wird und einen Punkt in den Ordnernamen einfügt. Die Funktion gibt den Punkt am Ende des Ordners zurück. Daher ist es besser, wenn der Benutzer zunächst überprüft, ob der angegebene Name ein Dateiname und kein Ordnername ist.

Eine NET/CLI-Version, die System::String verwendet

   System::String^ GetFileExtension(System::String^ FileName)
   {
       int Ext=FileName->LastIndexOf('.');
       if( Ext != -1 )
           return FileName->Substring(Ext+1);
       return "";
   }

Ich würde mitgehen boost::filesystem::extension Wenn Sie Boost jedoch nicht verwenden können und nur die Erweiterung überprüfen müssen, ist eine einfache Lösung:

bool ends_with(const std::string &filename, const std::string &ext)
{
  return ext.length() <= filename.length() &&
         std::equal(ext.rbegin(), ext.rend(), filename.rbegin());
}

if (ends_with(filename, ".conf"))
{ /* ... */ }

Ich verwende diese beiden Funktionen, um das zu erhalten Verlängerung Und Dateiname ohne Erweiterung:

std::string fileExtension(std::string file){

    std::size_t found = file.find_last_of(".");
    return file.substr(found+1);

}

std::string fileNameWithoutExtension(std::string file){

    std::size_t found = file.find_last_of(".");
    return file.substr(0,found);    
}

Und diese regex Ansätze für bestimmte Zusatzanforderungen:

std::string fileExtension(std::string file){

    std::regex re(".*[^\\.]+\\.([^\\.]+$)");
    std::smatch result;
    if(std::regex_match(file,result,re))return result[1];
    else return "";

}

std::string fileNameWithoutExtension(std::string file){

    std::regex re("(.*[^\\.]+)\\.[^\\.]+$");
    std::smatch result;
    if(std::regex_match(file,result,re))return result[1];
    else return file;

}

Zusätzliche Anforderungen, die von der Regex-Methode erfüllt werden:

  1. Wenn Dateiname ist wie .config oder so ähnlich, Verlängerung wird eine leere Zeichenfolge sein und Dateiname ohne Erweiterung wird sein .config.
  2. Wenn der Dateiname keine Erweiterung hat, ist die Erweiterung eine leere Zeichenfolge. Dateiname ohne Erweiterung wird sein Dateiname unverändert.

BEARBEITEN:

Die zusätzlichen Anforderungen können auch durch Folgendes erfüllt werden:

std::string fileExtension(const std::string& file){
    std::string::size_type pos=file.find_last_of('.');
    if(pos!=std::string::npos&&pos!=0)return file.substr(pos+1);
    else return "";
}


std::string fileNameWithoutExtension(const std::string& file){
    std::string::size_type pos=file.find_last_of('.');
    if(pos!=std::string::npos&&pos!=0)return file.substr(0,pos);
    else return file;
}

Notiz:

Übergeben Sie in den oben genannten Funktionen nur die Dateinamen (nicht den Pfad).

Versuchen zu benutzen strstr

char* lastSlash;
lastSlash = strstr(filename, ".");

Oder Sie können Folgendes verwenden:

    char *ExtractFileExt(char *FileName)
    {
        std::string s = FileName;
        int Len = s.length();
        while(TRUE)
        {
            if(FileName[Len] != '.')
                Len--;
            else
            {
                char *Ext = new char[s.length()-Len+1];
                for(int a=0; a<s.length()-Len; a++)
                    Ext[a] = FileName[s.length()-(s.length()-Len)+a];
                Ext[s.length()-Len] = '\0';
                return Ext;
            }
        }
    }

Dieser Code ist plattformübergreifend

Wenn Sie die Qt-Bibliothek verwenden, können Sie es versuchen QFileInfo'S Suffix()

Hier ist eine Funktion, die einen Pfad/Dateinamen als String akzeptiert und die Erweiterung als String zurückgibt.Es ist alles Standard-C++ und sollte auf den meisten Plattformen plattformübergreifend funktionieren.

Im Gegensatz zu einigen anderen Antworten hier werden die seltsamen Fälle behandelt, die PathFindExtension von Windows behandelt, basierend auf der Dokumentation von PathFindExtensions.

wstring get_file_extension( wstring filename )
{
    size_t last_dot_offset = filename.rfind(L'.');
    // This assumes your directory separators are either \ or /
    size_t last_dirsep_offset = max( filename.rfind(L'\\'), filename.rfind(L'/') );

    // no dot = no extension
    if( last_dot_offset == wstring::npos )
        return L"";

    // directory separator after last dot = extension of directory, not file.
    // for example, given C:\temp.old\file_that_has_no_extension we should return "" not "old"
    if( (last_dirsep_offset != wstring::npos) && (last_dirsep_offset > last_dot_offset) )
        return L"";

    return filename.substr( last_dot_offset + 1 );
}

Dies ist eine Lösung, die ich gefunden habe.Dann ist mir aufgefallen, dass es dem ähnelt, was @serengeor gepostet hat.

Es funktioniert mit std::string Und find_last_of, aber die Grundidee funktioniert auch, wenn sie für die Verwendung modifiziert wird char Arrays und strrchr.Es verarbeitet versteckte Dateien und zusätzliche Punkte, die das aktuelle Verzeichnis darstellen.Es ist plattformunabhängig.

string PathGetExtension( string const & path )
{
  string ext;

  // Find the last dot, if any.
  size_t dotIdx = path.find_last_of( "." );
  if ( dotIdx != string::npos )
  {
    // Find the last directory separator, if any.
    size_t dirSepIdx = path.find_last_of( "/\\" );

    // If the dot is at the beginning of the file name, do not treat it as a file extension.
    // e.g., a hidden file:  ".alpha".
    // This test also incidentally avoids a dot that is really a current directory indicator.
    // e.g.:  "alpha/./bravo"
    if ( dotIdx > dirSepIdx + 1 )
    {
      ext = path.substr( dotIdx );
    }
  }

  return ext;
}

Gerätetest:

int TestPathGetExtension( void )
{
  int errCount = 0;

  string tests[][2] = 
  {
    { "/alpha/bravo.txt", ".txt" },
    { "/alpha/.bravo", "" },
    { ".alpha", "" },
    { "./alpha.txt", ".txt" },
    { "alpha/./bravo", "" },
    { "alpha/./bravo.txt", ".txt" },
    { "./alpha", "" },
    { "c:\\alpha\\bravo.net\\charlie.txt", ".txt" },
  };

  int n = sizeof( tests ) / sizeof( tests[0] );

  for ( int i = 0; i < n; ++i )
  {
    string ext = PathGetExtension( tests[i][0] );
    if ( ext != tests[i][1] )
    {
      ++errCount;
    }
  }

  return errCount;
}

Wenn Sie es zufällig verwenden Poco Bibliotheken, die Sie machen können:

#include <Poco/Path.h>

...

std::string fileExt = Poco::Path("/home/user/myFile.abc").getExtension(); // == "abc"

Wenn Sie die Erweiterung als letzten Punkt und die möglichen Zeichen danach betrachten, jedoch nur, wenn diese kein Verzeichnistrennzeichen enthalten, gibt die folgende Funktion den Startindex der Erweiterung zurück oder -1, wenn keine Erweiterung gefunden wurde.Wenn Sie das haben, können Sie tun, was immer Sie wollen, z. B. die Erweiterung entfernen, ändern, überprüfen usw.

long get_extension_index(string path, char dir_separator = '/') {
    // Look from the end for the first '.',
    // but give up if finding a dir separator char first
    for(long i = path.length() - 1; i >= 0; --i) {
        if(path[i] == '.') {
            return i;
        }
        if(path[i] == dir_separator) {
            return -1;
        }
    }
    return -1;
}

Ich habe die Funktion PathFindExtension() verwendet, um herauszufinden, ob es sich um eine gültige TIF-Datei handelt oder nicht.

#include <Shlwapi.h>
bool A2iAWrapperUtility::isValidImageFile(string imageFile)
{
    char * pStrExtension = ::PathFindExtension(imageFile.c_str());

    if (pStrExtension != NULL && strcmp(pStrExtension, ".tif") == 0)
    {
        return true;
    }

    return false;
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top