Получить имя файла из пути

85

Какой самый простой способ получить имя файла из пути?

string filename = "C:\\MyDirectory\\MyFile.bat"

В этом примере я должен получить «MyFile». без расширения.

нидхал
источник
1
Искать со спины, пока не нажмете клавишу возврата?
Kerrek SB
2
@KerrekSB, вы имеете ввиду обратную косую черту ;)
Ним
У меня есть std :: string, которая содержит путь к файлу «c: \\ MyDirectory \\ Myfile.pdf», мне нужно переименовать этот файл в myfile_md.pdf, поэтому мне нужно получить имя файла из пути.
нидхал
1
Если вам нужно много работать с путями к файлам, подумайте об использовании Boost FileSystem boost.org/doc/libs/release/libs/filesystem/v3/doc/index.htm
edA-qa mort-ora-y
2
@ Ним: Да! Я, должно быть,
разошелся

Ответы:

29

_splitpath должен делать то, что вам нужно. Вы, конечно, можете сделать это вручную, но_splitpath обрабатывает все особые случаи.

РЕДАКТИРОВАТЬ:

Как упомянул BillHoag, рекомендуется использовать более безопасную версию _splitpathвызываемого _splitpath_s если она доступна.

Или, если вам нужно что-то портативное, вы можете просто сделать что-то вроде этого

std::vector<std::string> splitpath(
  const std::string& str
  , const std::set<char> delimiters)
{
  std::vector<std::string> result;

  char const* pch = str.c_str();
  char const* start = pch;
  for(; *pch; ++pch)
  {
    if (delimiters.find(*pch) != delimiters.end())
    {
      if (start != pch)
      {
        std::string str(start, pch);
        result.push_back(str);
      }
      else
      {
        result.push_back("");
      }
      start = pch + 1;
    }
  }
  result.push_back(start);

  return result;
}

...
std::set<char> delims{'\\'};

std::vector<std::string> path = splitpath("C:\\MyDirectory\\MyFile.bat", delims);
cout << path.back() << endl;
AndersK
источник
2
На _splitpathмоей машине нет ни одного из включений.
Джеймс Канце
9
У меня и Visual Studio, и g ++, и Sun CC. Зачем использовать что-то нестандартное, когда есть совершенно хорошие портативные решения.
Джеймс Канце
2
@James, на странице, на которую указана ссылка, написано, что он находится внутри <stdlib.h>. Что касается переносимости, возможно, вы можете перечислить несколько примеров «совершенно хороших портативных решений»?
Synetech
2
@Synetech Страница, на которую указана ссылка, описывает расширение Microsoft, а не <stdlib.h>. И самое очевидное портативное решение - это boost::filesystem.
Джеймс Канце
3
@James, вы не имеете _splitpathв stdlib.hвашей копии VS? Затем вы можете выполнить ремонтную установку VS.
Synetech
63

Возможное решение:

string filename = "C:\\MyDirectory\\MyFile.bat";

// Remove directory if present.
// Do this before extension removal incase directory has a period character.
const size_t last_slash_idx = filename.find_last_of("\\/");
if (std::string::npos != last_slash_idx)
{
    filename.erase(0, last_slash_idx + 1);
}

// Remove extension if present.
const size_t period_idx = filename.rfind('.');
if (std::string::npos != period_idx)
{
    filename.erase(period_idx);
}
hmjd
источник
самое простое - всегда лучшее!
Жан-Франсуа Фабр
61

Задача довольно проста, поскольку базовое имя файла - это просто часть строки, начинающаяся с последнего разделителя для папок:

std::string base_filename = path.substr(path.find_last_of("/\\") + 1)

Если расширение также должно быть удалено, единственное, что нужно сделать, это найти последнее .и перейти substrк этому моменту

std::string::size_type const p(base_filename.find_last_of('.'));
std::string file_without_extension = base_filename.substr(0, p);

Возможно, должна быть проверка, чтобы справиться с файлами, состоящими исключительно из расширений (т.е. .bashrc...)

Если вы разделите это на отдельные функции, вы сможете повторно использовать отдельные задачи:

template<class T>
T base_name(T const & path, T const & delims = "/\\")
{
  return path.substr(path.find_last_of(delims) + 1);
}
template<class T>
T remove_extension(T const & filename)
{
  typename T::size_type const p(filename.find_last_of('.'));
  return p > 0 && p != T::npos ? filename.substr(0, p) : filename;
}

Код создан по шаблону, чтобы можно было использовать его с разными std::basic_stringэкземплярами (например, std::string& std::wstring...)

Обратной стороной шаблона является требование указать параметр шаблона, если const char * функциям передается .

Итак, вы могли либо:

A) Используйте только std::stringвместо шаблонов кода

std::string base_name(std::string const & path)
{
  return path.substr(path.find_last_of("/\\") + 1);
}

Б) Предоставьте функцию обертывания с использованием std::string(в качестве промежуточных звеньев, которые, вероятно, будут встроены / оптимизированы)

inline std::string string_base_name(std::string const & path)
{
  return base_name(path);
}

В) Укажите параметр шаблона при вызове с помощью const char *.

std::string base = base_name<std::string>("some/path/file.ext");

Результат

std::string filepath = "C:\\MyDirectory\\MyFile.bat";
std::cout << remove_extension(base_name(filepath)) << std::endl;

Печать

MyFile
Pixelchemist
источник
В этом случае все в порядке (и на исходный вопрос дан ответ), но ваше средство для удаления расширений не идеально - оно не сработает, если мы передадим туда что-то вроде "/home/user/my.dir/myfile"
автоматон
@avtomaton Функцию удаления расширения следует использовать для имени файла, а не пути. (Просто base_nameсначала подайте заявку .)
Pixelchemist
Я это понимаю (поэтому я написал, что на исходный вопрос дан ответ, и в этом случае все в порядке). Просто хотел указать на эту проблему для тех, кто попытается использовать эти фрагменты.
автоматон
Очень красивое объяснение. Это улучшает структурное понимание проблемы. Спасибо
hell_ical_vortex
38

Самое простое решение - использовать что-то вроде boost::filesystem. Если по какой-то причине это не вариант ...

Делать это правильно потребует некоторой системы зависимого кода: под Windows, либо '\\'или '/'может быть разделителем пути; под Unix '/'работает только , а под другими системами, кто знает. Очевидное решение было бы примерно таким:

std::string
basename( std::string const& pathname )
{
    return std::string( 
        std::find_if( pathname.rbegin(), pathname.rend(),
                      MatchPathSeparator() ).base(),
        pathname.end() );
}

, с MatchPathSeparatorопределением в системно-зависимом заголовке как:

struct MatchPathSeparator
{
    bool operator()( char ch ) const
    {
        return ch == '/';
    }
};

для Unix или:

struct MatchPathSeparator
{
    bool operator()( char ch ) const
    {
        return ch == '\\' || ch == '/';
    }
};

для Windows (или что-то другое для другой неизвестной системы).

РЕДАКТИРОВАТЬ: Я упустил тот факт, что он также хотел подавить расширение. Для этого то же самое:

std::string
removeExtension( std::string const& filename )
{
    std::string::const_reverse_iterator
                        pivot
            = std::find( filename.rbegin(), filename.rend(), '.' );
    return pivot == filename.rend()
        ? filename
        : std::string( filename.begin(), pivot.base() - 1 );
}

Код немного сложнее, потому что в этом случае основание обратного итератора находится не на той стороне, где мы хотим вырезать. (Помните, что основание обратного итератора находится позади символа, на который указывает итератор.) И даже это немного сомнительно: мне не нравится, например, тот факт, что он может возвращать пустую строку. (Если единственный '.'символ - это первый символ имени файла, я бы поспорил, что вы должны вернуть полное имя файла. Для этого потребуется немного дополнительного кода, чтобы уловить особый случай.)}

Джеймс Канце
источник
9
Как насчет использования string::find_last_ofвместо манипулирования обратными итераторами?
Люк Турель
@LucTouraille Зачем изучать два способа делать что-то, когда один будет делать? Вам понадобятся обратные итераторы для любого контейнера, кроме string, так что вам все равно придется их изучить. А изучив их, нет причин беспокоиться о том, чтобы изучать весь раздутый интерфейс std::string.
Джеймс Канце
Примечание. Заголовок <filesystem> поставляется с Visual Studio 2015 и более поздними версиями, поэтому вам не нужно добавлять зависимость от ускорения для его использования.
IInspectable
16

Самый простой способ в C ++ 17:

используйте #include <filesystem>и filename()для имени файла с расширением и stem()без расширения.

    #include <iostream>
    #include <filesystem>
    namespace fs = std::filesystem;

    int main()
    {
        string filename = "C:\\MyDirectory\\MyFile.bat";

    std::cout << fs::path(filename).filename() << '\n'
        << fs::path(filename).stem() << '\n'
        << fs::path("/foo/bar.txt").filename() << '\n'
        << fs::path("/foo/bar.txt").stem() << '\n'
        << fs::path("/foo/.bar").filename() << '\n'
        << fs::path("/foo/bar/").filename() << '\n'
        << fs::path("/foo/.").filename() << '\n'
        << fs::path("/foo/..").filename() << '\n'
        << fs::path(".").filename() << '\n'
        << fs::path("..").filename() << '\n'
        << fs::path("/").filename() << '\n';
    }

вывод:

MyFile.bat
MyFile
"bar.txt"
".bar"
"."
"."
".."
"."
".."
"/"

Ссылка: cppreference

eliasetm
источник
это больше не в "экспериментальном"
Vit
15

Вы также можете использовать API-интерфейсы оболочки PathFindFileName, PathRemoveExtension. Возможно, хуже, чем _splitpath для этой конкретной проблемы, но эти API-интерфейсы очень полезны для всех видов заданий по синтаксическому анализу путей, и они принимают во внимание UNC-пути, косую черту и другие странные вещи.

wstring filename = L"C:\\MyDirectory\\MyFile.bat";
wchar_t* filepart = PathFindFileName(filename.c_str());
PathRemoveExtension(filepart); 

http://msdn.microsoft.com/en-us/library/windows/desktop/bb773589(v=vs.85).aspx

Недостатком является то, что вы должны ссылаться на shlwapi.lib, но я не совсем уверен, почему это недостаток.

Скрымсли
источник
Мое предпочтительное решение для получения имени файла из пути.
Андреас
15

Если вы можете использовать ускорение,

#include <boost/filesystem.hpp>
path p("C:\\MyDirectory\\MyFile.bat");
string basename = p.filename().string();
//or 
//string basename = path("C:\\MyDirectory\\MyFile.bat").filename().string();

Это все.

Я рекомендую вам использовать библиотеку boost. Boost дает вам много удобств при работе с C ++. Он поддерживает практически все платформы. Если вы используете Ubuntu, вы можете установить библиотеку boost только одной строкой sudo apt-get install libboost-all-dev(см. Как установить boost на Ubuntu? )

plhn
источник
12

Функция:

#include <string>

std::string
basename(const std::string &filename)
{
    if (filename.empty()) {
        return {};
    }

    auto len = filename.length();
    auto index = filename.find_last_of("/\\");

    if (index == std::string::npos) {
        return filename;
    }

    if (index + 1 >= len) {

        len--;
        index = filename.substr(0, len).find_last_of("/\\");

        if (len == 0) {
            return filename;
        }

        if (index == 0) {
            return filename.substr(1, len - 1);
        }

        if (index == std::string::npos) {
            return filename.substr(0, len);
        }

        return filename.substr(index + 1, len - index - 1);
    }

    return filename.substr(index + 1, len - index);
}

Тесты:

#define CATCH_CONFIG_MAIN
#include <catch/catch.hpp>

TEST_CASE("basename")
{
    CHECK(basename("") == "");
    CHECK(basename("no_path") == "no_path");
    CHECK(basename("with.ext") == "with.ext");
    CHECK(basename("/no_filename/") == "no_filename");
    CHECK(basename("no_filename/") == "no_filename");
    CHECK(basename("/no/filename/") == "filename");
    CHECK(basename("/absolute/file.ext") == "file.ext");
    CHECK(basename("../relative/file.ext") == "file.ext");
    CHECK(basename("/") == "/");
    CHECK(basename("c:\\windows\\path.ext") == "path.ext");
    CHECK(basename("c:\\windows\\no_filename\\") == "no_filename");
}
Риан Куинн
источник
8

Из документов C ++ - строка :: find_last_of

#include <iostream>       // std::cout
#include <string>         // std::string

void SplitFilename (const std::string& str) {
  std::cout << "Splitting: " << str << '\n';
  unsigned found = str.find_last_of("/\\");
  std::cout << " path: " << str.substr(0,found) << '\n';
  std::cout << " file: " << str.substr(found+1) << '\n';
}

int main () {
  std::string str1 ("/usr/bin/man");
  std::string str2 ("c:\\windows\\winhelp.exe");

  SplitFilename (str1);
  SplitFilename (str2);

  return 0;
}

Выходы:

Splitting: /usr/bin/man
 path: /usr/bin
 file: man
Splitting: c:\windows\winhelp.exe
 path: c:\windows
 file: winhelp.exe
jave.web
источник
Не забудьте (и обработать), что find_last_ofвозвращается, string::nposесли ничего не было найдено.
congusbongus
@congusbongus Верно, но нет смысла разделять путь к файлу, когда это всего лишь имя файла (без пути) :)
jave.web
@ jave.web Это имеет смысл и ДОЛЖЕН обрабатывать возвращаемые строки 'string :: npos'. Реализация функции для этого должна иметь возможность обрабатывать различные входные данные, включая «только имя файла». В противном случае он будет бесполезен, если он будет глючить в реальной реализации.
Winux
@winux Это учитывает уже действительные ПУТИ ... Если вы не доверяете вводимым данным, вы, конечно, должны сначала проверить путь.
jave.web
@winux В любом случае проверка string::nposне требуется из-за того, как это string::substrреализовано. a) string::npos передается как "length" => substrимеет задокументированное поведение чтения всего до конца. б) substrдается « string::npos + 1» и ни длина: string::nposне документирована , чтобы иметь значение -1, так что имеет значение 0=> начало строки и значения по умолчанию для длины substrявляетсяnpos => работает на „просто имя файла“ тоже cplusplus.com/reference / string / string / substr cplusplus.com/reference/string/string/npos
jave.web
5

Вариант C ++ 11 (вдохновленный версией Джеймса Канце) с унифицированной инициализацией и анонимной встроенной лямбдой.

std::string basename(const std::string& pathname)
{
    return {std::find_if(pathname.rbegin(), pathname.rend(),
                         [](char c) { return c == '/'; }).base(),
            pathname.end()};
}

Однако он не удаляет расширение файла.

альвеко
источник
Коротко и удобно, хотя работает только с путями, отличными от Windows.
Volomike 05
вы всегда можете изменить лямбда-возврат на, return c == '/' || c == '\\';чтобы он работал в Windows
ziomq1991
Для обработки таких путей, как «», «///» и «dir1 / dir2 /», добавьте следующий код перед оператором return выше (см. POSIX basename ()): if (pathname.size() == 0) return "."; auto iter = pathname.rbegin(); auto rend = pathname.rend(); while (iter != rend && *iter == '/') ++iter; if (iter == rend) /* pathname has only path separators */ return "/"; pathname = std::string(pathname.begin(), iter.base());
Gidfiddle
5

boost filesystemБиблиотека также доступна в качестве experimental/filesystemбиблиотеки и объединены в ISO C ++ для C ++ 17. Вы можете использовать это так:

#include <iostream>
#include <experimental/filesystem>

namespace fs = std::experimental::filesystem;

int main () {
    std::cout << fs::path("/foo/bar.txt").filename() << '\n'
}

Вывод:

"bar.txt"

Это также работает для std::stringобъектов.

Адам Эриксон
источник
4

это единственное, что действительно сработало для меня:

#include "Shlwapi.h"

CString some_string = "c:\\path\\hello.txt";
LPCSTR file_path = some_string.GetString();
LPCSTR filepart_c = PathFindFileName(file_path);
LPSTR filepart = LPSTR(filepart_c);
PathRemoveExtension(filepart);

в значительной степени то, что предложил Скримсли, но не работает с wchar_t *, VS Enterprise 2015

_splitpath тоже работал, но мне не нравится угадывать, сколько символов char [?] мне понадобится; Наверное, некоторым людям нужен этот контроль.

CString c_model_name = "c:\\path\\hello.txt";
char drive[200];
char dir[200];
char name[200];
char ext[200];
_splitpath(c_model_name, drive, dir, name, ext);

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

Фрактал
источник
4
std::string getfilename(std::string path)
{
    path = path.substr(path.find_last_of("/\\") + 1);
    size_t dot_i = path.find_last_of('.');
    return path.substr(0, dot_i);
}
Beyondo
источник
3

Я бы сделал это ...

Ищите в обратном направлении от конца строки, пока не найдете первую обратную / прямую косую черту.

Затем снова выполните поиск в обратном направлении от конца строки, пока не найдете первую точку (.)

Затем у вас есть начало и конец имени файла.

Простые ...

TomP89
источник
Что не работает ни в одной известной мне системе. (Одна система, которая принимает '\\'в качестве разделителя пути, также используется '/', поэтому вам нужно сопоставить и то, и другое.) И я не уверен, чего вы ждете.
Джеймс Канце
Хорошо, так что измените его, чтобы он соответствовал, не важно. И с нетерпением жду первой точки (.)
TomP89
Вам все равно нужно найти последнюю точку, а не первую. (Обратные итераторы - ваш друг!)
Джеймс Канце
Ах да, хорошее замечание. Итак, для file.ext.ext вы бы хотели извлечь file.ext, не так ли. :)
TomP89
Предположительно. В любом случае это обычное соглашение: например, my.source.cppкомпилируется my.source.obj.cppзаменой расширения на .obj).
Джеймс Канце
2
m_szFilePath.MakeLower();
CFileFind finder;
DWORD buffSize = MAX_PATH;
char longPath[MAX_PATH];
DWORD result = GetLongPathName(m_szFilePath, longPath, MAX_PATH );

if( result == 0)
{
    m_bExists = FALSE;
    return;
}
m_szFilePath = CString(longPath);
m_szFilePath.Replace("/","\\");
m_szFilePath.Trim();
//check if it does not ends in \ => remove it
int length = m_szFilePath.GetLength();
if( length > 0 && m_szFilePath[length - 1] == '\\' )
{
    m_szFilePath.Truncate( length - 1 );
}
BOOL bWorking = finder.FindFile(this->m_szFilePath);
if(bWorking){
    bWorking = finder.FindNextFile();
    finder.GetCreationTime(this->m_CreationTime);
    m_szFilePath = finder.GetFilePath();
    m_szFileName = finder.GetFileName();

    this->m_szFileExtension = this->GetExtension( m_szFileName );

    m_szFileTitle = finder.GetFileTitle();
    m_szFileURL = finder.GetFileURL();
    finder.GetLastAccessTime(this->m_LastAccesTime);
    finder.GetLastWriteTime(this->m_LastWriteTime);
    m_ulFileSize = static_cast<unsigned long>(finder.GetLength());
    m_szRootDirectory = finder.GetRoot();
    m_bIsArchive = finder.IsArchived();
    m_bIsCompressed = finder.IsCompressed();
    m_bIsDirectory = finder.IsDirectory();
    m_bIsHidden = finder.IsHidden();
    m_bIsNormal = finder.IsNormal();
    m_bIsReadOnly = finder.IsReadOnly();
    m_bIsSystem = finder.IsSystem();
    m_bIsTemporary = finder.IsTemporary();
    m_bExists = TRUE;
    finder.Close();
}else{
    m_bExists = FALSE;
}

Переменная m_szFileName содержит имя файла.

Люциан
источник
3
вау - это много кода для "получить имя файла" из пути ... :)
Ним
4
@Nim И мое впечатление. В моем собственном коде, я использую один вкладыш: boost::filesystem::path( path ).filename().
Джеймс Канце
У меня есть класс CFileInfo с этим кодом. Я просто сбросил код здесь, потому что он протестирован, и я не хотел ничем рисковать ... Вы можете просто использовать около 5 строк кода из этого примера.
Lucian
2

Не используйте _splitpath()и_wsplitpath() . Они небезопасны и устарели!

Вместо этого используйте их безопасные версии, а именно _splitpath_s()и_wsplitpath_s()

hkBattousai
источник
2

Это тоже должно работать:

// strPath = "C:\\Dir\\File.bat" for example
std::string getFileName(const std::string& strPath)
{
    size_t iLastSeparator = 0;
    return strPath.substr((iLastSeparator = strPath.find_last_of("\\")) != std::string::npos ? iLastSeparator + 1 : 0, strPath.size() - strPath.find_last_of("."));
}

Если вы можете его использовать, Qt предоставляет QString (с разделением, обрезкой и т.д.), QFile, QPath, QFileInfo и т.д. для управления файлами, именами файлов и каталогами. И, конечно же, это кросс-платформа.

typedef
источник
4
Ради будущих читателей вашего кода, пожалуйста, используйте временные переменные с осмысленными именами вместо того, чтобы помещать все в одну строку кода (и пока вы это делаете, пожалуйста, инкапсулируйте все это в функцию getFilenameили что-то в этом роде).
Люк Турель
отредактировал. Но суть заключалась в том, чтобы сделать его кратким, поскольку уже было дано несколько рабочих ответов.
typedef
1
Я думаю, что это НЕПРАВИЛЬНО. Не следует ли заменить последнюю часть: «strPath.size () - strPath.find_last_of («. »)» На «strPath.find_last_of («. ») - iLastSeparator»
taktak004
@ taktak004, вы правы, это должно быть `return strPath.substr ((iLastSeparator = strPath.find_last_of (" / "))! = std :: string :: npos? iLastSeparator + 1: 0, strPath.find_last_of (". ". ) - iLastSeparator); `
phenmod
2

Для этого вы можете использовать std :: filesystem:

#include <filesystem>
namespace fs = std::experimental::filesystem;

fs::path myFilePath("C:\\MyDirectory\\MyFile.bat");
fs::path filename = myFilePath.stem();
Управляемый взлом
источник
0

Я долго искал функцию, которая могла бы правильно разложить путь к файлу. Для меня этот код отлично работает как для Linux, так и для Windows.

void decomposePath(const char *filePath, char *fileDir, char *fileName, char *fileExt)
{
    #if defined _WIN32
        const char *lastSeparator = strrchr(filePath, '\\');
    #else
        const char *lastSeparator = strrchr(filePath, '/');
    #endif

    const char *lastDot = strrchr(filePath, '.');
    const char *endOfPath = filePath + strlen(filePath);
    const char *startOfName = lastSeparator ? lastSeparator + 1 : filePath;
    const char *startOfExt = lastDot > startOfName ? lastDot : endOfPath;

    if(fileDir)
        _snprintf(fileDir, MAX_PATH, "%.*s", startOfName - filePath, filePath);

    if(fileName)
        _snprintf(fileName, MAX_PATH, "%.*s", startOfExt - startOfName, startOfName);

    if(fileExt)
        _snprintf(fileExt, MAX_PATH, "%s", startOfExt);
}

Примеры результатов:

[]
  fileDir:  ''
  fileName: ''
  fileExt:  ''

[.htaccess]
  fileDir:  ''
  fileName: '.htaccess'
  fileExt:  ''

[a.exe]
  fileDir:  ''
  fileName: 'a'
  fileExt:  '.exe'

[a\b.c]
  fileDir:  'a\'
  fileName: 'b'
  fileExt:  '.c'

[git-archive]
  fileDir:  ''
  fileName: 'git-archive'
  fileExt:  ''

[git-archive.exe]
  fileDir:  ''
  fileName: 'git-archive'
  fileExt:  '.exe'

[D:\Git\mingw64\libexec\git-core\.htaccess]
  fileDir:  'D:\Git\mingw64\libexec\git-core\'
  fileName: '.htaccess'
  fileExt:  ''

[D:\Git\mingw64\libexec\git-core\a.exe]
  fileDir:  'D:\Git\mingw64\libexec\git-core\'
  fileName: 'a'
  fileExt:  '.exe'

[D:\Git\mingw64\libexec\git-core\git-archive.exe]
  fileDir:  'D:\Git\mingw64\libexec\git-core\'
  fileName: 'git-archive'
  fileExt:  '.exe'

[D:\Git\mingw64\libexec\git.core\git-archive.exe]
  fileDir:  'D:\Git\mingw64\libexec\git.core\'
  fileName: 'git-archive'
  fileExt:  '.exe'

[D:\Git\mingw64\libexec\git-core\git-archiveexe]
  fileDir:  'D:\Git\mingw64\libexec\git-core\'
  fileName: 'git-archiveexe'
  fileExt:  ''

[D:\Git\mingw64\libexec\git.core\git-archiveexe]
  fileDir:  'D:\Git\mingw64\libexec\git.core\'
  fileName: 'git-archiveexe'
  fileExt:  ''

Надеюсь, это вам тоже поможет :)

никто особенный
источник
0

shlwapi.lib/dll использует HKCU куст реестра для внутренних .

Лучше не ссылаться на shlwapi.lib если вы создаете библиотеку или продукт не имеет пользовательского интерфейса. Если вы пишете библиотеку, ваш код можно использовать в любом проекте, в том числе в тех, у которых нет пользовательского интерфейса.

Если вы пишете код, который запускается, когда пользователь не вошел в систему (например, служба [или другое] настроено на запуск при загрузке или запуске), то нет HKCU. Наконец, shlwapi - это расчетные функции; и, как следствие, стоит на первом месте в списке устаревших версий Windows.

Ручей
источник
0

Медленное, но простое решение с регулярным выражением:

    std::string file = std::regex_replace(path, std::regex("(.*\\/)|(\\..*)"), "");
Сава Б.
источник
0

Я реализовал функцию, которая может удовлетворить ваши потребности. Он основан на функции constexpr string_view find_last_of (начиная с C ++ 17), которая может быть вычислена во время компиляции

constexpr const char* base_filename(const char* p) {
    const size_t i = std::string_view(p).find_last_of('/');
    return std::string_view::npos == i ? p : p + i + 1 ;
}

//in the file you used this function
base_filename(__FILE__);
Чжиюнчжао
источник