How to get file extension from string in C++

前端 未结 25 2328
迷失自我
迷失自我 2020-11-30 22:35

Given a string \"filename.conf\", how to I verify the extension part?

I need a cross platform solution.

相关标签:
25条回答
  • 2020-11-30 23:11

    The best way is to not write any code that does it but call existing methods. In windows, the PathFindExtension method is probably the simplest.

    So why would you not write your own?

    Well, take the strrchr example, what happens when you use that method on the following string "c:\program files\AppleGate.Net\readme"? Is ".Net\readme" the extension? It is easy to write something that works for a few example cases, but can be much harder to write something that works for all cases.

    0 讨论(0)
  • 2020-11-30 23:11

    I use these two functions to get the extension and filename without extension:

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

    And these regex approaches for certain extra requirements:

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

    Extra requirements that are met by the regex method:

    1. If filename is like .config or something like this, extension will be an empty string and filename without extension will be .config.
    2. If filename doesn't have any extension, extention will be an empty string, filename without extension will be the filename unchanged.

    EDIT:

    The extra requirements can also be met by the following:

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

    Note:

    Pass only the filenames (not path) in the above functions.

    0 讨论(0)
  • 2020-11-30 23:14

    This is a solution I came up with. Then, I noticed that it is similar to what @serengeor posted.

    It works with std::string and find_last_of, but the basic idea will also work if modified to use char arrays and strrchr. It handles hidden files, and extra dots representing the current directory. It is platform independent.

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

    Unit test:

    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;
    }
    
    0 讨论(0)
  • 2020-11-30 23:15

    If you happen to use Poco libraries you can do:

    #include <Poco/Path.h>
    
    ...
    
    std::string fileExt = Poco::Path("/home/user/myFile.abc").getExtension(); // == "abc"
    
    0 讨论(0)
  • 2020-11-30 23:17

    Try to use strstr

    char* lastSlash;
    lastSlash = strstr(filename, ".");
    
    0 讨论(0)
  • 2020-11-30 23:18

    Someone else mentioned boost but I just wanted to add the actual code to do this:

    #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
    
    0 讨论(0)
提交回复
热议问题