Biorąc pod uwagę ciąg "filename.conf"
, jak zweryfikować część rozszerzenia?
Potrzebuję rozwiązania wieloplatformowego.
Odpowiedzi:
Musisz upewnić się, że dbasz o nazwy plików z więcej niż jedną kropką. przykład: c:\.directoryname\file.name.with.too.many.dots.ext
nie zostanie poprawnie obsłużony przez strchr
lubfind.
Moją ulubioną byłaby biblioteka systemu plików boost, która ma funkcję rozszerzenia (ścieżki)
Czy to zbyt proste rozwiązanie?
#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...";
bez sprawdzenia - zakłada się, że rozwiązanie powinno działać dla innych danych wejściowych. Jako inny przeciwny przykład, plik o nazwie po prostu „conf” bez rozszerzenia również zwróciłby „Tak ...”, biorąc pod uwagę powyższe.
boost::filesystem
, co jest trywialne w użyciu, ale zapewnia niezbędne wsparcie. Zobacz boost.org/doc/libs/1_55_0/libs/filesystem/doc/index.htm
Najlepszym sposobem jest nie pisanie kodu, który to robi, ale wywołanie istniejących metod. W systemie Windows metoda PathFindExtension jest prawdopodobnie najprostsza.
Więc dlaczego nie miałbyś napisać własnego?
Cóż, weźmy przykład strrchr, co się stanie, gdy użyjesz tej metody w następującym ciągu „c: \ program files \ AppleGate.Net \ readme”? Czy „.Net \ readme” jest rozszerzeniem? Łatwo jest napisać coś, co działa w kilku przykładowych przypadkach, ale może być znacznie trudniej napisać coś, co działa we wszystkich przypadkach.
Zakładając, że masz dostęp do 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
}
Edycja: jest to rozwiązanie wieloplatformowe, ponieważ nie wspomniałeś o platformie. Jeśli korzystasz z systemu Windows, będziesz chciał wykorzystać specyficzne funkcje systemu Windows wspomniane przez innych w wątku.
Ktoś inny wspomniał o wzmocnieniu, ale chciałem tylko dodać rzeczywisty kod, aby to zrobić:
#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
w rzeczywistości STL może to zrobić bez dużej ilości kodu, radzę dowiedzieć się trochę o STL, ponieważ pozwala ci zrobić kilka wymyślnych rzeczy, w każdym razie tego używam.
std::string GetFileExtension(const std::string& FileName)
{
if(FileName.find_last_of(".") != std::string::npos)
return FileName.substr(FileName.find_last_of(".")+1);
return "";
}
to rozwiązanie zawsze zwróci rozszerzenie, nawet w przypadku łańcuchów typu „this.abcdesmp3”, jeśli nie może znaleźć rozszerzenia, zwróci „”.
Z C ++ 17 i jego std::filesystem::path::extension
(biblioteka jest następcą boost :: filesystem) uczyniłbyś swoją instrukcję bardziej ekspresyjną niż użycie np 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"
}
}
Zobacz także std :: filesystem :: path :: stem , std :: filesystem :: path :: filename .
Sam natknąłem się dzisiaj na to pytanie, chociaż miałem już działający kod, zorientowałem się, że w niektórych przypadkach nie zadziała.
Podczas gdy niektórzy już sugerowali użycie zewnętrznych bibliotek, ja wolę pisać własny kod do celów edukacyjnych.
Niektóre odpowiedzi zawierały metodę, której użyłem w pierwszej kolejności (szukanie ostatniego „.”), Ale pamiętałem, że w Linuksie ukryte pliki / foldery zaczynają się od „.”. Więc jeśli plik jest ukryty i nie ma rozszerzenia, cała nazwa pliku zostanie wzięta za rozszerzenie. Aby tego uniknąć, napisałem ten fragment kodu:
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;
}
Nie testowałem tego w pełni, ale myślę, że powinno działać.
Użycie funkcji find / rfind std :: string rozwiązuje TEN problem, ale jeśli dużo pracujesz ze ścieżkami, powinieneś spojrzeć na boost :: filesystem :: path, ponieważ sprawi, że twój kod będzie znacznie czystszy niż majstrowanie przy indeksach / iteratorach ciągów.
Sugeruję ulepszenie, ponieważ jest to wysokiej jakości, dobrze przetestowana (open source i komercyjnie) bezpłatna iw pełni przenośna biblioteka.
W przypadku łańcuchów znaków typu tablica możesz użyć tego:
#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;
}
Obsługuje ścieżki plików oprócz nazw plików. Działa z C i C ++. I wieloplatformowy.
strlen(extension)
w for
stanie. Następnie, jeśli znaki nie pasują, zwróć false. for
Pętla zewnętrzna zwraca prawdę.
Dobre odpowiedzi, ale widzę, że większość z nich ma pewne problemy: Przede wszystkim uważam, że dobra odpowiedź powinna działać w przypadku pełnych nazw plików, które mają swoje nagłówki ścieżek, a także powinna działać dla systemu Linux lub Windows lub, jak wspomniano, powinna być wieloplatformowa. W przypadku większości odpowiedzi; nazwy plików bez rozszerzenia, ale ścieżka z nazwą folderu zawierającą kropkę, funkcja nie zwróci prawidłowego rozszerzenia: przykłady niektórych przypadków testowych mogą wyglądać następująco:
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
Sugestia „ brian newman ” nie powiedzie się dla nazwy pliku1 i nazwy pliku4. a większość innych odpowiedzi opartych na wyszukiwaniu wstecznym nie powiedzie się dla nazwy_pliku1. Proponuję uwzględnić w źródle następującą metodę: która jest funkcją zwracającą indeks pierwszego znaku rozszerzenia lub długość podanego ciągu, jeśli nie zostanie znaleziony.
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;
}
możesz użyć powyższego kodu w swojej aplikacji c ++, jak poniżej:
std::string get_file_ext(const char* fileName)
{
return std::string(fileName).substr(find_ext_idx(fileName));
}
W ostatnim punkcie w niektórych przypadkach folder a jest podawany jako argument jako nazwa pliku i zawiera kropkę w nazwie folderu, funkcja zwróci kropkę folderu na końcu, aby użytkownik najpierw sprawdził, czy podana nazwa jest nazwą pliku, a nie nazwą folderu.
Wersja NET / CLI używająca System :: String
System::String^ GetFileExtension(System::String^ FileName)
{
int Ext=FileName->LastIndexOf('.');
if( Ext != -1 )
return FileName->Substring(Ext+1);
return "";
}
Poszedłbym z boost::filesystem::extension
( std::filesystem::path::extension
z C ++ 17), ale jeśli nie możesz użyć Boost i musisz tylko zweryfikować rozszerzenie, prostym rozwiązaniem jest:
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"))
{ /* ... */ }
To jest rozwiązanie, które wymyśliłem. Potem zauważyłem, że jest podobny do tego, co opublikował @serengeor.
Działa z std::string
i find_last_of
, ale podstawowa idea zadziała również, jeśli zostanie zmodyfikowana do używania char
tablic i strrchr
. Obsługuje ukryte pliki i dodatkowe kropki reprezentujące bieżący katalog. Jest niezależny od platformy.
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;
}
Test jednostkowy:
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;
}
Używam tych dwóch funkcji, aby uzyskać rozszerzenie i nazwę pliku bez rozszerzenia :
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);
}
I te regex
podejścia dla pewnych dodatkowych wymagań:
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;
}
Dodatkowe wymagania, które spełnia metoda regex:
.config
lub podobna do tego, rozszerzenie będzie pustym ciągiem, a nazwa pliku bez rozszerzenia będzie.config
.EDYTOWAĆ:
Dodatkowe wymagania mogą być również spełnione przez:
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;
}
Uwaga:
Przekaż tylko nazwy plików (nie ścieżki) w powyższych funkcjach.
Lub możesz użyć tego:
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;
}
}
}
Ten kod jest wieloplatformowy
Jeśli korzystasz z biblioteki Qt, można dać spróbować QFileInfo jest przyrostkiem ()
Oto funkcja, która pobiera ścieżkę / nazwę pliku jako ciąg i zwraca rozszerzenie jako ciąg. To wszystko jest w standardzie C ++ i powinno działać na wielu platformach dla większości platform.
W przeciwieństwie do kilku innych odpowiedzi tutaj, obsługuje dziwne przypadki, które obsługuje PathFindExtension systemu Windows, na podstawie dokumentacji 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'/') )
porówna dwie wartości bez znaku, jedną z nich może być npos
największa możliwa liczba całkowita bez znaku. Więc może wyglądać, że nie ma folderu, nawet jeśli tam jest!
Jeśli korzystasz z bibliotek Poco , możesz:
#include <Poco/Path.h>
...
std::string fileExt = Poco::Path("/home/user/myFile.abc").getExtension(); // == "abc"
Jeśli uznasz rozszerzenie za ostatnią kropkę i możliwe znaki po niej, ale tylko wtedy, gdy nie zawierają one znaku separatora katalogu, poniższa funkcja zwraca indeks początkowy rozszerzenia lub -1, jeśli nie znaleziono rozszerzenia. Kiedy już to masz, możesz robić, co chcesz, na przykład zdjąć rozszerzenie, zmienić, sprawdzić itp.
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;
}
Użyłem funkcji PathFindExtension (), aby dowiedzieć się, czy jest to prawidłowy plik tif, czy nie.
#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;
}
Możesz użyć strrchr (), aby znaleźć ostatnie wystąpienie plików rozszerzeń. (Kropka) i pobrać. (Kropka). Sprawdź na przykład poniższy kod.
#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;
}