"filename.conf"
Wie überprüfe ich anhand einer Zeichenfolge den Erweiterungsteil?
Ich brauche eine plattformübergreifende Lösung.
Antworten:
Sie müssen sicherstellen, dass Sie sich um Dateinamen mit mehr als einem Punkt kümmern. Beispiel: c:\.directoryname\file.name.with.too.many.dots.ext
würde von strchr
oder nicht richtig behandeltfind.
Mein Favorit wäre die Boost-Dateisystembibliothek mit einer Erweiterungsfunktion (Pfad)
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;
}
}
return "Yes...";
keine Prüfung gibt - dies impliziert, dass die Lösung für andere Eingaben funktionieren sollte. Als weiteres Zählerbeispiel würde eine Datei mit dem Namen "conf" ohne Erweiterung angesichts der obigen Angaben auch "Ja ..." zurückgeben.
boost::filesystem
, was trivial zu benutzen ist, aber die notwendige Unterstützung bietet. Siehe boost.org/doc/libs/1_55_0/libs/filesystem/doc/index.htm
Der beste Weg ist, keinen Code zu schreiben, der dies tut, sondern vorhandene Methoden aufzurufen. In Windows ist die PathFindExtension- Methode wahrscheinlich die einfachste.
Warum sollten Sie nicht Ihre eigenen schreiben?
Nehmen Sie das Beispiel strrchr. Was passiert, wenn Sie diese Methode für die folgende Zeichenfolge "c: \ Programme \ AppleGate.Net \ readme" verwenden? Ist ".Net \ readme" 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.
Angenommen, 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, möchten Sie die Windows-spezifischen Funktionen nutzen, die von anderen im Thread erwähnt werden.
Jemand anderes erwähnte Boost, 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 rate Ihnen, etwas über die STL zu lernen, da Sie damit einige ausgefallene Dinge tun können. Jedenfalls ist dies das, was ich verwende.
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 die Erweiterung auch bei Zeichenfolgen wie "this.abcdesmp3" immer zurück, wenn sie die zurückgegebene Erweiterung nicht finden kann.
Mit C ++ 17 und seiner std::filesystem::path::extension
(die Bibliothek ist der Nachfolger von boost :: filesystem) würden Sie Ihre Aussage ausdrucksvoller machen als z 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 .
Eigentlich ist der einfachste Weg
char* ext;
ext = strrchr(filename,'.')
Eine Sache, an die Sie sich erinnern sollten: Wenn '.'
der Dateiname nicht vorhanden ist, ist ext NULL
.
Ich bin heute selbst auf diese Frage gestoßen, obwohl ich bereits einen funktionierenden Code hatte, stellte ich fest, dass er in einigen Fällen nicht funktionieren würde.
Während einige Leute bereits vorgeschlagen haben, einige externe Bibliotheken zu verwenden, schreibe ich lieber meinen eigenen Code für Lernzwecke.
Einige Antworten enthielten die Methode, die ich zuerst verwendet hatte (auf der Suche nach dem letzten "."), Aber ich erinnerte mich, dass versteckte Dateien / Ordner unter Linux mit "." Beginnen. Wenn die Dateidatei ausgeblendet ist und keine Erweiterung hat, wird der gesamte Dateiname als Erweiterung verwendet. Um dies 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 dies nicht vollständig getestet, aber ich denke, dass es funktionieren sollte.
Die Verwendung von find / rfind von std :: string löst DIESES Problem. Wenn Sie jedoch viel mit Pfaden arbeiten, sollten Sie sich boost :: filesystem :: path ansehen, da dies Ihren Code viel sauberer macht als das Fummeln mit rohen String-Indizes / Iteratoren.
Ich schlage Boost vor, 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 array 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 mit C ++. Und plattformübergreifend.
strlen(extension)
in einwandfreiem for
Zustand. Wenn die Zeichen nicht übereinstimmen, geben Sie false zurück. Außerhalb der for
Schleife return true.
Gute Antworten, aber ich sehe, dass die meisten von ihnen einige Probleme haben: Zunächst denke ich, dass eine gute Antwort für vollständige Dateinamen mit ihren Pfadüberschriften funktionieren sollte, auch für Linux oder Windows oder wie erwähnt plattformübergreifend. Für die meisten Antworten; Dateinamen ohne Erweiterung, aber mit einem Pfad mit einem Ordnernamen einschließlich Punkt. Die Funktion gibt nicht die richtige Erweiterung zurück: Beispiele für einige Testfälle könnten 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
Der Vorschlag " brian newman " schlägt für Dateiname1 und Dateiname4 fehl. und die meisten anderen Antworten, die auf Reverse Find basieren, schlagen für Dateiname1 fehl. Ich schlage vor, die folgende Methode in Ihre Quelle aufzunehmen: Diese Funktion gibt den Index des ersten Zeichens der Erweiterung oder die Länge der angegebenen Zeichenfolge zurück, 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önnen den obigen Code in Ihrer C ++ - Anwendung wie folgt verwenden:
std::string get_file_ext(const char* fileName)
{
return std::string(fileName).substr(find_ext_idx(fileName));
}
Der letzte Punkt in einigen Fällen ist, dass ein Ordner dem Dateinamen als Argument zugewiesen wird und einen Punkt im Ordnernamen enthält. Die Funktion gibt die Punktverfolgung des Ordners zurück. Überprüfen Sie daher besser zuerst, ob der angegebene Name ein Dateiname und kein Ordnername ist.
Eine NET / CLI-Version mit System :: String
System::String^ GetFileExtension(System::String^ FileName)
{
int Ext=FileName->LastIndexOf('.');
if( Ext != -1 )
return FileName->Substring(Ext+1);
return "";
}
Ich würde mit boost::filesystem::extension
( std::filesystem::path::extension
mit C ++ 17) gehen, aber wenn Sie Boost 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"))
{ /* ... */ }
Dies ist eine Lösung, die ich mir ausgedacht habe. Dann bemerkte ich, dass es ähnlich ist wie das, was @serengeor gepostet hat.
Es funktioniert mit std::string
und find_last_of
, aber die Grundidee funktioniert auch, wenn sie geändert wird, um char
Arrays und zu verwenden 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;
}
Ich benutze diese beiden Funktionen, um die Erweiterung und den Dateinamen ohne Erweiterung zu erhalten :
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 zusätzliche Anforderungen:
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:
.config
oder so etwas, Erweiterung wird ein leerer String und sein Dateinamen ohne Erweiterung sein wird .config
.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;
}
Hinweis:
Übergeben Sie in den obigen Funktionen nur die Dateinamen (nicht den Pfad).
Oder Sie können dies 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
Hier ist eine Funktion, die einen Pfad / Dateinamen als Zeichenfolge verwendet und die Erweiterung als Zeichenfolge zurückgibt. Es ist alles Standard-C ++ und sollte für die meisten Plattformen plattformübergreifend funktionieren.
Im Gegensatz zu mehreren anderen Antworten werden hier die ungewöhnlichen 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 );
}
max( filename.rfind(L'\\'), filename.rfind(L'/') )
werden zwei vorzeichenlose Werte verglichen, von denen einer npos
die größtmögliche vorzeichenlose Ganzzahl sein kann. Es könnte also so aussehen, als gäbe es keinen Ordner, selbst wenn er da ist!
Wenn Sie zufällig Poco- Bibliotheken verwenden, können Sie Folgendes tun:
#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, aber nur, wenn sie nicht das Verzeichnis-Trennzeichen 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, wie 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 festzustellen, 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;
}
Sie können strrchr () verwenden , um das letzte Vorkommen von. (Punkt) zu finden und. (Punkt) -basierte Erweiterungsdateien abzurufen. Überprüfen Sie zum Beispiel den folgenden Code.
#include<stdio.h>
void GetFileExtension(const char* file_name) {
int ext = '.';
const char* extension = NULL;
extension = strrchr(file_name, ext);
if(extension == NULL){
printf("Invalid extension encountered\n");
return;
}
printf("File extension is %s\n", extension);
}
int main()
{
const char* file_name = "c:\\.directoryname\\file.name.with.too.many.dots.ext";
GetFileExtension(file_name);
return 0;
}