Как получить расширение файла из строки в C ++ - PullRequest
73 голосов
/ 09 сентября 2008

Учитывая строку "filename.conf", как проверить часть расширения?

Мне нужно кроссплатформенное решение.

Ответы [ 24 ]

3 голосов
/ 09 ноября 2014

Хорошие ответы, но я вижу, что у большинства из них есть некоторые проблемы: Прежде всего, я думаю, что хороший ответ должен работать для полных имен файлов, имеющих заголовки пути, также он должен работать для 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

" brian newman " не удастся выполнить для filename1 и filename4. и большинство других ответов, основанных на обратном поиске, потерпят неудачу для filename1. Я предлагаю включить следующий метод в ваш источник: которая является функцией, возвращающей индекс первого символа расширения или длину заданной строки, если она не найдена.

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));
}

Последний пункт в некоторых случаях папка присваивается имени файла в качестве аргумента и включает точку в имени папки, функция будет возвращать точку в конце папки, поэтому лучше сначала проверить, что данное имя является именем файла, а не папкой имя.

3 голосов
/ 14 декабря 2009

Использование std :: string find / rfind решает ЭТУ проблему, но если вы много работаете с путями, вам следует взглянуть на boost :: filesystem :: path, так как это сделает ваш код намного чище, чем возиться с необработанными строковыми индексами / итераторы.

Я предлагаю boost, поскольку это высококачественная, хорошо протестированная, (с открытым исходным кодом и коммерчески) бесплатная и полностью переносимая библиотека.

3 голосов
/ 24 января 2011

Для строк типа 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 ++. И кроссплатформенный.

3 голосов
/ 26 июля 2011

Версия NET / CLI с использованием System :: String

   System::String^ GetFileExtension(System::String^ FileName)
   {
       int Ext=FileName->LastIndexOf('.');
       if( Ext != -1 )
           return FileName->Substring(Ext+1);
       return "";
   }
2 голосов
/ 19 августа 2015

Я использую эти две функции, чтобы получить расширение и имя файла без расширения :

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;

}

Дополнительные требования, которым удовлетворяет метод регулярных выражений:

  1. Если имя файла похоже на .config или что-то вроде этого, расширение будет пустой строкой, а имя файла без расширения будет .config.
  2. Если имя файла не имеет расширения, расширение будет пустой строкой, имя файла без расширения будет имя файла без изменений.

EDIT:

Дополнительные требования также могут быть выполнены:

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;
}

Примечание:

Передавать только имена файлов (не пути) в вышеуказанных функциях.

2 голосов
/ 02 мая 2015

Я бы пошел с boost::filesystem::extension, но если вы не можете использовать 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"))
{ /* ... */ }
1 голос
/ 20 августа 2015

Это решение, которое я придумал. Затем я заметил, что это похоже на то, что написал @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;
}
1 голос
/ 28 апреля 2014

Вот функция, которая принимает путь / имя файла в виде строки и возвращает расширение в виде строки. Это все стандарт c ++, и он должен работать кроссплатформенно для большинства платформ.

В отличие от нескольких других ответов здесь, он обрабатывает нечетные случаи, которые обрабатывает Windows PathFindExtension, основываясь на документации 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 );
}
1 голос
/ 02 марта 2014

Если вы используете библиотеку Qt, вы можете попробовать QFileInfo ' суффикс ()

1 голос
/ 07 августа 2013

Или вы можете использовать это:

    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;
            }
        }
    }

Этот код является кроссплатформенным

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...