Враховуючи рядок "filename.conf"
, як перевірити частину розширення?
Мені потрібне рішення для різних платформ.
Відповіді:
Ви повинні подбати про те, щоб піклуватися про імена файлів із кількома крапками. приклад: c:\.directoryname\file.name.with.too.many.dots.ext
неправильно оброблятиметься strchr
абоfind.
Моїм улюбленим буде бібліотека файлової системи boost, яка має функцію розширення (шлях)
Це надто просте рішення?
#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...";
не перевіряючи взагалі - мається на увазі, що рішення повинно працювати для інших входів. Як інший приклад лічильника, файл із назвою просто "conf" без розширення також поверне "Так ...", враховуючи вищезазначене.
boost::filesystem
, що є простим у використанні, але надає необхідну підтримку. Дивіться boost.org/doc/libs/1_55_0/libs/filesystem/doc/index.htm
Найкращий спосіб - це не писати код, який це робить, а викликати існуючі методи. У вікнах метод PathFindExtension є, мабуть, найпростішим.
То чому б вам не написати своє?
Ну, візьмемо приклад strrchr, що відбувається, коли ви використовуєте цей метод у такому рядку "c: \ program files \ AppleGate.Net \ readme"? Чи є ".Net \ readme" розширенням? Легко написати щось, що працює для кількох прикладів, але може бути набагато складніше написати щось, що працює для всіх випадків.
Припускаючи, що у вас є доступ до 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
}
Редагувати: Це рішення для різних платформ, оскільки ви не згадали про платформу. Якщо ви спеціально працюєте в ОС Windows, ви захочете використати певні функції Windows, згадані іншими в потоці.
Хтось ще згадав про підвищення, але я просто хотів додати власне код, щоб зробити це:
#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
насправді STL може робити це без особливого коду, я раджу вам трохи дізнатись про STL, тому що це дозволяє робити деякі вигадливі речі, в будь-якому випадку я цим і користуюся.
std::string GetFileExtension(const std::string& FileName)
{
if(FileName.find_last_of(".") != std::string::npos)
return FileName.substr(FileName.find_last_of(".")+1);
return "";
}
це рішення завжди повертає розширення навіть у таких рядках, як "this.abcdesmp3", якщо воно не може знайти розширення, воно поверне "".
З C ++ 17 та його std::filesystem::path::extension
(бібліотека є наступницею boost :: filesystem) ви зробили б своє висловлювання більш виразним, ніж використання наприклад 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"
}
}
Див. Також std :: filesystem :: path :: stem , std :: filesystem :: path :: filename .
Я сам натрапив на це питання сьогодні, хоча, маючи вже діючий код, я зрозумів, що в деяких випадках він не спрацює.
Хоча деякі люди вже пропонували використовувати деякі зовнішні бібліотеки, я вважаю за краще писати власний код для навчальних цілей.
Деякі відповіді включали метод, яким я користувався в першу чергу (шукаючи останній "."), Але я пам'ятав, що в Linux приховані файли / папки починаються з ".". Отже, якщо файл файлу прихований і не має розширення, ціле ім’я файлу буде прийнято за розширення. Щоб уникнути цього, я написав цей фрагмент коду:
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;
}
Я не перевірив це повністю, але вважаю, що це має спрацювати.
Використання функції std :: string find / rfind вирішує ЦЮ проблему, але якщо ви багато працюєте зі шляхами, тоді вам слід поглянути на boost :: filesystem :: path, оскільки це зробить ваш код набагато чистішим, ніж базікання з необробленими індексами рядків / ітераторами.
Я пропоную посилити, оскільки це високоякісна, добре перевірена, (з відкритим кодом та комерційно) безкоштовна та повністю портативна бібліотека.
Для рядків типу масиву char ви можете використовувати це:
#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;
}
Може обробляти шляхи до файлів на додаток до імен файлів. Працює як з C, так і з C ++. І крос-платформний.
strlen(extension)
у for
стані. Тоді, якщо символ chars не відповідає, поверніть false. Зовнішній for
цикл повертає true.
Хороші відповіді, але я бачу, що у більшості з них є деякі проблеми: Перш за все, я думаю, що хороша відповідь повинна працювати для повних імен файлів, які мають заголовки шляхів, також вона повинна працювати для Linux або Windows, або, як уже згадувалося, вона повинна бути міжплатформною. Для більшості відповідей; імена файлів без розширення, але шлях із назвою папки, включаючи крапку, функція не зможе повернути правильне розширення: приклади деяких тестових випадків можуть бути такими:
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
Пропозиція " Брайан Ньюман " не буде виконана для файлів file1 та file4 . і більшість інших відповідей, які базуються на зворотному пошуку, не зможуть отримати ім'я файлу1. Я пропоную включити до вашого джерела наступний метод: це функція, що повертає індекс першого символу розширення або довжину заданого рядка, якщо не знайдено.
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;
}
ви можете використовувати наведений вище код у вашому додатку c ++, як показано нижче:
std::string get_file_ext(const char* fileName)
{
return std::string(fileName).substr(find_ext_idx(fileName));
}
Останній пункт, в деяких випадках папці присвоюється ім'я файлу як аргумент і включає крапку в назві папки, функція повертає крапку папки, так краще спочатку користувачеві перевірити, що вказане ім'я є ім'ям файлу, а не ім'ям папки.
Версія NET / CLI з використанням System :: String
System::String^ GetFileExtension(System::String^ FileName)
{
int Ext=FileName->LastIndexOf('.');
if( Ext != -1 )
return FileName->Substring(Ext+1);
return "";
}
Я б пішов із boost::filesystem::extension
( std::filesystem::path::extension
з C ++ 17), але якщо ви не можете використовувати Boost і вам просто потрібно перевірити розширення, просте рішення:
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"))
{ /* ... */ }
Це рішення я придумав. Потім я помітив, що це схоже на те, що розміщував @serengeor.
Він працює з std::string
та find_last_of
, але основна ідея також буде працювати, якщо його змінити для використання char
масивів та strrchr
. Він обробляє приховані файли та додаткові крапки, що представляють поточний каталог. Це не залежить від платформи.
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;
}
Одиничний тест:
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;
}
Я використовую ці дві функції, щоб отримати розширення та ім'я файлу без розширення :
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);
}
І ці regex
підходи для певних додаткових вимог:
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;
}
Додаткові вимоги, яким відповідає метод регулярного виразу:
.config
або щось подібне, розширення буде порожнім рядком, а ім'я файлу без розширення буде .config
.РЕДАГУВАТИ:
Додаткові вимоги також можуть відповідати наступним:
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;
}
Примітка:
Передайте лише назви файлів (а не шлях) у вищевказаних функціях.
Або ви можете використовувати це:
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;
}
}
}
Цей код є крос-платформним
Якщо ви використовуєте бібліотеку Qt, ви можете дати спробувати на QFileInfo «s суфікса ()
Ось функція, яка приймає шлях / ім'я файлу як рядок і повертає розширення як рядок. Це все стандартний c ++, і він повинен працювати на різних платформах для більшості платформ.
На відміну від кількох інших відповідей тут, він обробляє дивні випадки, які обробляє PathFindExtention вікон, на основі документації 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'/') )
буде порівнюватися два беззнакові значення, одне з яких може бути npos
найбільшим з можливих цілих беззнакових. Тож може здатися, що папки немає навіть тоді, коли вона там є!
Якщо ви випадково користуєтесь бібліотеками Poco, ви можете зробити:
#include <Poco/Path.h>
...
std::string fileExt = Poco::Path("/home/user/myFile.abc").getExtension(); // == "abc"
Якщо ви розглядаєте розширення як останню крапку та можливі символи після неї, але лише якщо вони не містять символу розділювача каталогів, наступна функція повертає початковий індекс розширення або -1, якщо розширення не знайдено. Коли у вас є, ви можете робити все, що завгодно, наприклад, зняти розширення, змінити його, перевірити тощо.
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;
}
Я використовував функцію PathFindExtension (), щоб дізнатись, чи є це дійсним файлом TIF чи ні.
#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;
}
Ви можете використовувати strrchr (), щоб знайти останню появу. (Крапка) та отримати файли розширень на основі. (Крапка). Наприклад, перевірте наведений нижче код.
#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;
}