<p>Given a string <code>"filename.conf"</code>, how to I verify the extension part?</p>

<p>I need a cross platform solution.</p>

[{'answer_id': 51965, 'author': 'Aardvark', 'author_id': 3655, 'author_profile': 'https://Stackoverflow.com/users/3655', 'pm_score': 2, 'selected': False, 'text': '<pre><code>_splitpath, _wsplitpath, _splitpath_s, _wsplitpath_w\n</code></pre>\n\n<p>This is Windows (Platform SDK) only</p>\n'}, {'answer_id': 51992, 'author': '17 of 26', 'author_id': 2284, 'author_profile': 'https://Stackoverflow.com/users/2284', 'pm_score': 5, 'selected': False, 'text': '<p>Assuming you have access to STL:</p>\n\n<pre><code>std::string filename("filename.conf");\nstd::string::size_type idx;\n\nidx = filename.rfind(\'.\');\n\nif(idx != std::string::npos)\n{\n    std::string extension = filename.substr(idx+1);\n}\nelse\n{\n    // No extension found\n}\n</code></pre>\n\n<p><strong>Edit:</strong> This is a cross platform solution since you didn\'t mention the platform.  If you\'re specifically on Windows, you\'ll want to leverage the Windows specific functions mentioned by others in the thread.</p>\n'}, {'answer_id': 51993, 'author': 'Torlack', 'author_id': 5243, 'author_profile': 'https://Stackoverflow.com/users/5243', 'pm_score': 5, 'selected': False, 'text': '<p>The best way is to not write any code that does it but call existing methods.  In windows, the <a href="http://msdn.microsoft.com/en-us/library/bb773587(VS.85).aspx" rel="noreferrer" title="PathFindExtension">PathFindExtension</a> method is probably the simplest.</p>\n\n<p>So why would you not write your own?</p>\n\n<p>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.</p>\n'}, {'answer_id': 51999, 'author': 'brian newman', 'author_id': 3210, 'author_profile': 'https://Stackoverflow.com/users/3210', 'pm_score': 7, 'selected': False, 'text': '<p>Is this too simple of a solution?</p>\n\n<pre><code>#include &lt;iostream&gt;\n#include &lt;string&gt;\n\nint main()\n{\n  std::string fn = "filename.conf";\n  if(fn.substr(fn.find_last_of(".") + 1) == "conf") {\n    std::cout &lt;&lt; "Yes..." &lt;&lt; std::endl;\n  } else {\n    std::cout &lt;&lt; "No..." &lt;&lt; std::endl;\n  }\n}\n</code></pre>\n'}, {'answer_id': 52009, 'author': 'Community', 'author_id': -1, 'author_profile': 'https://Stackoverflow.com/users/-1', 'pm_score': 6, 'selected': True, 'text': '<p>You have to make sure you take care of file names with more then one dot. \nexample: <code>c:\\.directoryname\\file.name.with.too.many.dots.ext</code> would not be handled correctly by <code>strchr</code> or <code>find.</code> </p>\n\n<p>My favorite would be the <a href="http://www.boost.org/doc/libs/release/libs/filesystem/index.html" rel="noreferrer">boost filesystem library</a> that have an extension(path) function</p>\n'}, {'answer_id': 1897858, 'author': 'KristianR', 'author_id': 225550, 'author_profile': 'https://Stackoverflow.com/users/225550', 'pm_score': 2, 'selected': False, 'text': "<p>Using std::string's find/rfind solves THIS problem, but if you work a lot with paths then you should look at boost::filesystem::path since it will make your code much cleaner than fiddling with raw string indexes/iterators.</p>\n\n<p>I suggest boost since it's a high quality, well tested, (open source and commercially) free and fully portable library.</p>\n"}, {'answer_id': 4505931, 'author': 'graphitemaster', 'author_id': 550752, 'author_profile': 'https://Stackoverflow.com/users/550752', 'pm_score': 4, 'selected': False, 'text': '<p>actually the STL can do this without much code, I advise you learn a bit about the STL because it lets you do some fancy things, anyways this is what I use.</p>\n\n<pre><code>std::string GetFileExtension(const std::string&amp; FileName)\n{\n    if(FileName.find_last_of(".") != std::string::npos)\n        return FileName.substr(FileName.find_last_of(".")+1);\n    return "";\n}\n</code></pre>\n\n<p>this solution will always return the extension even on strings like "this.a.b.c.d.e.s.mp3" if it cannot find the extension it will return "".</p>\n'}, {'answer_id': 4777391, 'author': 'delaccount992', 'author_id': 554785, 'author_profile': 'https://Stackoverflow.com/users/554785', 'pm_score': 2, 'selected': False, 'text': '<p>For char array-type strings you can use this:</p>\n\n<pre><code>#include &lt;ctype.h&gt;\n#include &lt;string.h&gt;\n\nint main()\n{\n    char filename[] = "apples.bmp";\n    char extension[] = ".jpeg";\n\n    if(compare_extension(filename, extension) == true)\n    {\n        // .....\n    } else {\n        // .....\n    }\n\n    return 0;\n}\n\nbool compare_extension(char *filename, char *extension)\n{\n    /* Sanity checks */\n\n    if(filename == NULL || extension == NULL)\n        return false;\n\n    if(strlen(filename) == 0 || strlen(extension) == 0)\n        return false;\n\n    if(strchr(filename, \'.\') == NULL || strchr(extension, \'.\') == NULL)\n        return false;\n\n    /* Iterate backwards through respective strings and compare each char one at a time */\n\n    for(int i = 0; i &lt; strlen(filename); i++)\n    {\n        if(tolower(filename[strlen(filename) - i - 1]) == tolower(extension[strlen(extension) - i - 1]))\n        {\n            if(i == strlen(extension) - 1)\n                return true;\n        } else\n            break;\n    }\n\n    return false;\n}\n</code></pre>\n\n<p>Can handle file paths in addition to filenames. Works with both C and C++. And cross-platform.</p>\n'}, {'answer_id': 6821673, 'author': 'Leopoldo Sanczyk', 'author_id': 862270, 'author_profile': 'https://Stackoverflow.com/users/862270', 'pm_score': 2, 'selected': False, 'text': '<p>A NET/CLI version using System::String</p>\n\n<pre><code>   System::String^ GetFileExtension(System::String^ FileName)\n   {\n       int Ext=FileName-&gt;LastIndexOf(\'.\');\n       if( Ext != -1 )\n           return FileName-&gt;Substring(Ext+1);\n       return "";\n   }\n</code></pre>\n'}, {'answer_id': 10547576, 'author': 'Maadiah', 'author_id': 853569, 'author_profile': 'https://Stackoverflow.com/users/853569', 'pm_score': 0, 'selected': False, 'text': '<p>Try to use <a href="http://www.cplusplus.com/reference/clibrary/cstring/strstr/" rel="nofollow">strstr</a></p>\n\n<pre><code>char* lastSlash;\nlastSlash = strstr(filename, ".");\n</code></pre>\n'}, {'answer_id': 12792194, 'author': 'peter karasev', 'author_id': 221802, 'author_profile': 'https://Stackoverflow.com/users/221802', 'pm_score': 5, 'selected': False, 'text': '<p>Someone else mentioned boost but I just wanted to add the actual code to do this:</p>\n\n<pre><code>#include &lt;boost/filesystem.hpp&gt;\nusing std::string;\nstring texture         = foo-&gt;GetTextureFilename();\nstring file_extension  = boost::filesystem::extension(texture);\ncout &lt;&lt; "attempting load texture named " &lt;&lt; texture\n     &lt;&lt; "    whose extensions seems to be " \n     &lt;&lt; file_extension &lt;&lt; endl;\n// Use JPEG or PNG loader function, or report invalid extension\n</code></pre>\n'}, {'answer_id': 13430107, 'author': 'serengeor', 'author_id': 1636911, 'author_profile': 'https://Stackoverflow.com/users/1636911', 'pm_score': 3, 'selected': False, 'text': '<p>I\'ve stumbled onto this question today myself, even though I already had a working code I figured out that it wouldn\'t work in some cases.</p>\n\n<p>While some people already suggested using some external libraries, I prefer to write my own code for learning purposes.</p>\n\n<p>Some answers included the method I was using in the first place (looking for the last "."), but I remembered that on linux hidden files/folders start with ".".\nSo if file file is hidden and has no extension, the whole file name would be taken for extension.\nTo avoid that I wrote this piece of code:</p>\n\n<pre><code>bool getFileExtension(const char * dir_separator, const std::string &amp; file, std::string &amp; ext)\n{\n    std::size_t ext_pos = file.rfind(".");\n    std::size_t dir_pos = file.rfind(dir_separator);\n\n    if(ext_pos&gt;dir_pos+1)\n    {\n        ext.append(file.begin()+ext_pos,file.end());\n        return true;\n    }\n\n    return false;\n}\n</code></pre>\n\n<p>I haven\'t tested this fully, but I think that it should work.</p>\n'}, {'answer_id': 17944468, 'author': 'Qiu', 'author_id': 2572285, 'author_profile': 'https://Stackoverflow.com/users/2572285', 'pm_score': 3, 'selected': False, 'text': "<p>Actually, the easiest way is </p>\n\n<pre><code>char* ext;\next = strrchr(filename,'.') \n</code></pre>\n\n<p>One thing to remember: if <code>'.'</code> doesn't exist in filename, ext will be <code>NULL</code>.</p>\n"}, {'answer_id': 18100652, 'author': 'Quest', 'author_id': 2660282, 'author_profile': 'https://Stackoverflow.com/users/2660282', 'pm_score': 0, 'selected': False, 'text': "<p>Or you can use this:</p>\n\n<pre><code>    char *ExtractFileExt(char *FileName)\n    {\n        std::string s = FileName;\n        int Len = s.length();\n        while(TRUE)\n        {\n            if(FileName[Len] != '.')\n                Len--;\n            else\n            {\n                char *Ext = new char[s.length()-Len+1];\n                for(int a=0; a&lt;s.length()-Len; a++)\n                    Ext[a] = FileName[s.length()-(s.length()-Len)+a];\n                Ext[s.length()-Len] = '\\0';\n                return Ext;\n            }\n        }\n    }\n</code></pre>\n\n<p>This code is cross-platform</p>\n"}, {'answer_id': 22126750, 'author': 'Mark Kahn', 'author_id': 1171730, 'author_profile': 'https://Stackoverflow.com/users/1171730', 'pm_score': 2, 'selected': False, 'text': '<p>If you use Qt library, you can give a try to <a href="http://qt-project.org/doc/qt-4.8/qfileinfo.html" rel="nofollow">QFileInfo</a>\'s <a href="http://qt-project.org/doc/qt-4.8/qfileinfo.html#suffix" rel="nofollow">suffix()</a></p>\n'}, {'answer_id': 23346778, 'author': 'tfinniga', 'author_id': 9042, 'author_profile': 'https://Stackoverflow.com/users/9042', 'pm_score': 1, 'selected': False, 'text': '<p>Here\'s a function that takes a path/filename as a string and returns the extension as a string.  It is all standard c++, and should work cross-platform for most platforms.</p>\n\n<p>Unlike several other answers here, it handles the odd cases that windows\' PathFindExtension handles, based on PathFindExtensions\'s documentation.</p>\n\n<pre><code>wstring get_file_extension( wstring filename )\n{\n    size_t last_dot_offset = filename.rfind(L\'.\');\n    // This assumes your directory separators are either \\ or /\n    size_t last_dirsep_offset = max( filename.rfind(L\'\\\\\'), filename.rfind(L\'/\') );\n\n    // no dot = no extension\n    if( last_dot_offset == wstring::npos )\n        return L"";\n\n    // directory separator after last dot = extension of directory, not file.\n    // for example, given C:\\temp.old\\file_that_has_no_extension we should return "" not "old"\n    if( (last_dirsep_offset != wstring::npos) &amp;&amp; (last_dirsep_offset &gt; last_dot_offset) )\n        return L"";\n\n    return filename.substr( last_dot_offset + 1 );\n}\n</code></pre>\n'}, {'answer_id': 26822961, 'author': 'AMCoded', 'author_id': 1146097, 'author_profile': 'https://Stackoverflow.com/users/1146097', 'pm_score': 2, 'selected': False, 'text': '<p>Good answers but I see most of them has some problems:\nFirst of all I think a good answer should work for complete file names which have their path headings, also it should work for linux or windows or as mentioned it should be cross platform. For most of answers; file names with no extension but a path with a folder name including dot, the function will fail to return the correct extension: examples of some test cases could be as follow:</p>\n\n<pre><code>    const char filename1 = {"C:\\\\init.d\\\\doc"}; // =&gt; No extention\n    const char filename2 = {"..\\\\doc"}; //relative path name =&gt; No extention\n    const char filename3 = {""}; //emputy file name =&gt; No extention\n    const char filename4 = {"testing"}; //only single name =&gt; No extention\n    const char filename5 = {"tested/k.doc"}; // normal file name =&gt; doc\n    const char filename6 = {".."}; // parent folder =&gt; No extention\n    const char filename7 = {"/"}; // linux root =&gt; No extention\n    const char filename8 = {"/bin/test.d.config/lx.wize.str"}; // ordinary path! =&gt; str\n</code></pre>\n\n<p>"<em>brian newman</em>" suggestion will fail for filename1 and filename4.\nand most of other answers which are based on reverse find will fail for filename1.\nI suggest including the following method in your source:\nwhich is function returning index of first character of extension or the length of given string if not found.</p>\n\n<pre><code>size_t find_ext_idx(const char* fileName)\n{\n    size_t len = strlen(fileName);\n    size_t idx = len-1;\n    for(size_t i = 0; *(fileName+i); i++) {\n        if (*(fileName+i) == \'.\') {\n            idx = i;\n        } else if (*(fileName + i) == \'/\' || *(fileName + i) == \'\\\\\') {\n            idx = len - 1;\n        }\n    }\n    return idx+1;\n}\n</code></pre>\n\n<p>you could use the above code in your c++ application like below:</p>\n\n<pre><code>std::string get_file_ext(const char* fileName)\n{\n    return std::string(fileName).substr(find_ext_idx(fileName));\n}\n</code></pre>\n\n<p>The last point in some cases the a folder is given to file name as argument and includes a dot in the folder name the function will return folder\'s dot trailing so better first to user check that the given name is a filename and not folder name.</p>\n'}, {'answer_id': 30005179, 'author': 'manlio', 'author_id': 3235496, 'author_profile': 'https://Stackoverflow.com/users/3235496', 'pm_score': 2, 'selected': False, 'text': '<p>I\'d go with <a href="http://www.boost.org/doc/libs/1_58_0/libs/filesystem/doc/reference.html#path-extension" rel="nofollow noreferrer"><code>boost::filesystem::extension</code></a> (<a href="https://en.cppreference.com/w/cpp/filesystem/path/extension" rel="nofollow noreferrer"><code>std::filesystem::path::extension</code></a> with C++17) but if you cannot use Boost and you just have to verify the extension, a simple solution is:</p>\n\n<pre><code>bool ends_with(const std::string &amp;filename, const std::string &amp;ext)\n{\n  return ext.length() &lt;= filename.length() &amp;&amp;\n         std::equal(ext.rbegin(), ext.rend(), filename.rbegin());\n}\n\nif (ends_with(filename, ".conf"))\n{ /* ... */ }\n</code></pre>\n'}, {'answer_id': 32104638, 'author': 'Jahid', 'author_id': 3744681, 'author_profile': 'https://Stackoverflow.com/users/3744681', 'pm_score': 1, 'selected': False, 'text': '<p>I use these two functions to get the <em>extension</em> and <em>filename without extension</em>:</p>\n\n<pre><code>std::string fileExtension(std::string file){\n\n    std::size_t found = file.find_last_of(".");\n    return file.substr(found+1);\n\n}\n\nstd::string fileNameWithoutExtension(std::string file){\n\n    std::size_t found = file.find_last_of(".");\n    return file.substr(0,found);    \n}\n</code></pre>\n\n<p>And these <code>regex</code> approaches for certain extra requirements:</p>\n\n<pre><code>std::string fileExtension(std::string file){\n\n    std::regex re(".*[^\\\\.]+\\\\.([^\\\\.]+$)");\n    std::smatch result;\n    if(std::regex_match(file,result,re))return result[1];\n    else return "";\n\n}\n\nstd::string fileNameWithoutExtension(std::string file){\n\n    std::regex re("(.*[^\\\\.]+)\\\\.[^\\\\.]+$");\n    std::smatch result;\n    if(std::regex_match(file,result,re))return result[1];\n    else return file;\n\n}\n</code></pre>\n\n<p>Extra requirements that are met by the regex method:</p>\n\n<ol>\n<li>If <em>filename</em> is like <code>.config</code> or something like this, <em>extension</em> will be an empty string and <em>filename without extension</em> will be <code>.config</code>.</li>\n<li>If filename doesn\'t have any extension, extention will be an empty string, <em>filename without extension</em> will be the <em>filename</em> unchanged.</li>\n</ol>\n\n<hr>\n\n<p><strong>EDIT:</strong></p>\n\n<p>The extra requirements can also be met by the following:</p>\n\n<pre><code>std::string fileExtension(const std::string&amp; file){\n    std::string::size_type pos=file.find_last_of(\'.\');\n    if(pos!=std::string::npos&amp;&amp;pos!=0)return file.substr(pos+1);\n    else return "";\n}\n\n\nstd::string fileNameWithoutExtension(const std::string&amp; file){\n    std::string::size_type pos=file.find_last_of(\'.\');\n    if(pos!=std::string::npos&amp;&amp;pos!=0)return file.substr(0,pos);\n    else return file;\n}\n</code></pre>\n\n<p><strong>Note:</strong></p>\n\n<p>Pass only the filenames (not path) in the above functions.</p>\n'}, {'answer_id': 32105859, 'author': 'Mike Finch', 'author_id': 4577467, 'author_profile': 'https://Stackoverflow.com/users/4577467', 'pm_score': 2, 'selected': False, 'text': '<p>This is a solution I came up with.  Then, I noticed that it is similar to what @serengeor posted.</p>\n\n<p>It works with <code>std::string</code> and <code>find_last_of</code>, but the basic idea will also work if modified to use <code>char</code> arrays and <code>strrchr</code>.\nIt handles hidden files, and extra dots representing the current directory.  It is platform independent.</p>\n\n<pre><code>string PathGetExtension( string const &amp; path )\n{\n  string ext;\n\n  // Find the last dot, if any.\n  size_t dotIdx = path.find_last_of( "." );\n  if ( dotIdx != string::npos )\n  {\n    // Find the last directory separator, if any.\n    size_t dirSepIdx = path.find_last_of( "/\\\\" );\n\n    // If the dot is at the beginning of the file name, do not treat it as a file extension.\n    // e.g., a hidden file:  ".alpha".\n    // This test also incidentally avoids a dot that is really a current directory indicator.\n    // e.g.:  "alpha/./bravo"\n    if ( dotIdx &gt; dirSepIdx + 1 )\n    {\n      ext = path.substr( dotIdx );\n    }\n  }\n\n  return ext;\n}\n</code></pre>\n\n<p>Unit test:</p>\n\n<pre><code>int TestPathGetExtension( void )\n{\n  int errCount = 0;\n\n  string tests[][2] = \n  {\n    { "/alpha/bravo.txt", ".txt" },\n    { "/alpha/.bravo", "" },\n    { ".alpha", "" },\n    { "./alpha.txt", ".txt" },\n    { "alpha/./bravo", "" },\n    { "alpha/./bravo.txt", ".txt" },\n    { "./alpha", "" },\n    { "c:\\\\alpha\\\\bravo.net\\\\charlie.txt", ".txt" },\n  };\n\n  int n = sizeof( tests ) / sizeof( tests[0] );\n\n  for ( int i = 0; i &lt; n; ++i )\n  {\n    string ext = PathGetExtension( tests[i][0] );\n    if ( ext != tests[i][1] )\n    {\n      ++errCount;\n    }\n  }\n\n  return errCount;\n}\n</code></pre>\n'}, {'answer_id': 33729793, 'author': 'Darien Pardinas', 'author_id': 1416294, 'author_profile': 'https://Stackoverflow.com/users/1416294', 'pm_score': -1, 'selected': False, 'text': '<p>If you happen to use <a href="http://pocoproject.org/" rel="nofollow">Poco</a> libraries you can do:</p>\n\n<pre><code>#include &lt;Poco/Path.h&gt;\n\n...\n\nstd::string fileExt = Poco::Path("/home/user/myFile.abc").getExtension(); // == "abc"\n</code></pre>\n'}, {'answer_id': 34332887, 'author': 'Yuval', 'author_id': 4498825, 'author_profile': 'https://Stackoverflow.com/users/4498825', 'pm_score': -1, 'selected': False, 'text': "<p>If you consider the extension as the last dot and the possible characters after it, but only if they don't contain the directory separator character, the following function returns the extension starting index, or -1 if no extension found. When you have that you can do what ever you want, like strip the extension, change it, check it etc.</p>\n\n<pre><code>long get_extension_index(string path, char dir_separator = '/') {\n    // Look from the end for the first '.',\n    // but give up if finding a dir separator char first\n    for(long i = path.length() - 1; i &gt;= 0; --i) {\n        if(path[i] == '.') {\n            return i;\n        }\n        if(path[i] == dir_separator) {\n            return -1;\n        }\n    }\n    return -1;\n}\n</code></pre>\n"}, {'answer_id': 34906539, 'author': 'Pabitra Dash', 'author_id': 2776571, 'author_profile': 'https://Stackoverflow.com/users/2776571', 'pm_score': -1, 'selected': False, 'text': '<p>I used PathFindExtension() function to know whether it is a valid tif file or not.</p>\n\n<pre><code>#include &lt;Shlwapi.h&gt;\nbool A2iAWrapperUtility::isValidImageFile(string imageFile)\n{\n    char * pStrExtension = ::PathFindExtension(imageFile.c_str());\n\n    if (pStrExtension != NULL &amp;&amp; strcmp(pStrExtension, ".tif") == 0)\n    {\n        return true;\n    }\n\n    return false;\n}\n</code></pre>\n'}, {'answer_id': 50881646, 'author': 'Roi Danton', 'author_id': 4566599, 'author_profile': 'https://Stackoverflow.com/users/4566599', 'pm_score': 5, 'selected': False, 'text': '<p>With C++17 and its <a href="http://en.cppreference.com/w/cpp/filesystem/path/extension" rel="noreferrer"><code>std::filesystem::path::extension</code></a> (the library is the successor to boost::filesystem) you would make your statement more expressive than using e.g. <code>std::string</code>.</p>\n\n<pre><code>#include &lt;iostream&gt;\n#include &lt;filesystem&gt; // C++17\nnamespace fs = std::filesystem;\n\nint main()\n{\n    fs::path filePath = "my/path/to/myFile.conf";\n    if (filePath.extension() == ".conf") // Heed the dot.\n    {\n        std::cout &lt;&lt; filePath.stem() &lt;&lt; " is a valid type."; // Output: "myFile is a valid type."\n    }\n    else\n    {\n        std::cout &lt;&lt; filePath.filename() &lt;&lt; " is an invalid type."; // Output: e.g. "myFile.cfg is an invalid type"\n    }\n}\n</code></pre>\n\n<p>See also <a href="http://en.cppreference.com/w/cpp/filesystem/path/stem" rel="noreferrer">std::filesystem::path::stem</a>, <a href="http://en.cppreference.com/w/cpp/filesystem/path/filename" rel="noreferrer">std::filesystem::path::filename</a>.</p>\n'}, {'answer_id': 59923175, 'author': 'Haseeb Mir', 'author_id': 6219626, 'author_profile': 'https://Stackoverflow.com/users/6219626', 'pm_score': 2, 'selected': False, 'text': '<p>You can use <strong>strrchr()</strong> to find last occurence of .(dot) and get .(dot) based extensions files.\nCheck the below code for example.</p>\n\n<pre><code>#include&lt;stdio.h&gt;\n\nvoid GetFileExtension(const char* file_name) {\n\n    int ext = \'.\';\n    const char* extension = NULL;\n    extension = strrchr(file_name, ext);\n\n    if(extension == NULL){\n        printf("Invalid extension encountered\\n");\n        return;\n    }\n\n    printf("File extension is %s\\n", extension);\n}\n\nint main()\n{\n    const char* file_name = "c:\\\\.directoryname\\\\file.name.with.too.many.dots.ext";\n    GetFileExtension(file_name);\n    return 0;\n}\n</code></pre>\n'}, {'answer_id': 71945957, 'author': 'Jason C', 'author_id': 616460, 'author_profile': 'https://Stackoverflow.com/users/616460', 'pm_score': 0, 'selected': False, 'text': '<p>So, <a href="https://stackoverflow.com/a/50881646/616460">using <code>std::filesystem</code> is the best answer</a>, but if for whatever reason you don\'t have C++17 features available, this will work even if the input string includes directories:</p>\n<pre><code>string getextn (const string &amp;fn) {\n  int sep = fn.find_last_of(&quot;.\\\\/&quot;);\n  return (sep &gt;= 0 &amp;&amp; fn[sep] == \'.\') ? fn.substr(sep) : &quot;&quot;;\n}\n</code></pre>\n<p>I\'m adding this because the rest of the answers here are either strangely complicated or fail if the path to the file contains a dot and the file doesn\'t. I think the fact that <code>find_last_of</code> can look for multiple characters is often overlooked.</p>\n<p>It works with both <code>/</code> and <code>\\</code> path separators. It fails if the extension itself contains a slash but that\'s usually too rare to matter. It doesn\'t do any filtering for filenames that start with a dot and contain no other dots -- if this matters to you then <a href="https://stackoverflow.com/a/13430107/616460">this</a> is the least unreasonable answer here.</p>\n<p><a href="https://ideone.com/uwgMkE" rel="nofollow noreferrer">Example input / output</a>:</p>\n<pre class="lang-none prettyprint-override"><code>/ =&gt; \'\'\n./ =&gt; \'\'\n./pathname/ =&gt; \'\'\n./path.name/ =&gt; \'\'\npathname/ =&gt; \'\'\npath.name/ =&gt; \'\'\nc:\\path.name\\ =&gt; \'\'\n/. =&gt; \'.\'\n./. =&gt; \'.\'\n./pathname/. =&gt; \'.\'\n./path.name/. =&gt; \'.\'\npathname/. =&gt; \'.\'\npath.name/. =&gt; \'.\'\nc:\\path.name\\. =&gt; \'.\'\n/.git_ignore =&gt; \'.git_ignore\'\n./.git_ignore =&gt; \'.git_ignore\'\n./pathname/.git_ignore =&gt; \'.git_ignore\'\n./path.name/.git_ignore =&gt; \'.git_ignore\'\npathname/.git_ignore =&gt; \'.git_ignore\'\npath.name/.git_ignore =&gt; \'.git_ignore\'\nc:\\path.name\\.git_ignore =&gt; \'.git_ignore\'\n/filename =&gt; \'\'\n./filename =&gt; \'\'\n./pathname/filename =&gt; \'\'\n./path.name/filename =&gt; \'\'\npathname/filename =&gt; \'\'\npath.name/filename =&gt; \'\'\nc:\\path.name\\filename =&gt; \'\'\n/filename. =&gt; \'.\'\n./filename. =&gt; \'.\'\n./pathname/filename. =&gt; \'.\'\n./path.name/filename. =&gt; \'.\'\npathname/filename. =&gt; \'.\'\npath.name/filename. =&gt; \'.\'\nc:\\path.name\\filename. =&gt; \'.\'\n/filename.tar =&gt; \'.tar\'\n./filename.tar =&gt; \'.tar\'\n./pathname/filename.tar =&gt; \'.tar\'\n./path.name/filename.tar =&gt; \'.tar\'\npathname/filename.tar =&gt; \'.tar\'\npath.name/filename.tar =&gt; \'.tar\'\nc:\\path.name\\filename.tar =&gt; \'.tar\'\n/filename.tar.gz =&gt; \'.gz\'\n./filename.tar.gz =&gt; \'.gz\'\n./pathname/filename.tar.gz =&gt; \'.gz\'\n./path.name/filename.tar.gz =&gt; \'.gz\'\npathname/filename.tar.gz =&gt; \'.gz\'\npath.name/filename.tar.gz =&gt; \'.gz\'\nc:\\path.name\\filename.tar.gz =&gt; \'.gz\'\n</code></pre>\n'}]
['https://Stackoverflow.com/questions/51949', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/445087/']