Obtener un nombre de archivo de una ruta


82

¿Cuál es la forma más sencilla de obtener el nombre de archivo de una ruta?

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

En este ejemplo, debería obtener "MyFile". sin extensión.


1
¿Buscar desde atrás hasta llegar a un retroceso?
Kerrek SB

2
@KerrekSB, te refieres a barra invertida ;)
Nim

Tengo un std :: string que contiene una ruta de un archivo "c: \\ MyDirectory \\ Myfile.pdf" Necesito cambiar el nombre de este archivo a myfile_md.pdf, así que necesito obtener el nombre de archivo de la ruta.
nidhal

1
Si necesita trabajar mucho con rutas de archivo, considere usar Boost FileSystem boost.org/doc/libs/release/libs/filesystem/v3/doc/index.htm
edA-qa mort-ora-y

2
@Nim: ¡Sí! Debo haber estado espaciando ...
Kerrek SB

Respuestas:


29

_splitpath debería hacer lo que necesita. Por supuesto, puede hacerlo manualmente, pero también _splitpathmaneja todos los casos especiales.

EDITAR:

Como mencionó BillHoag, se recomienda usar la versión más segura de _splitpathllamada _splitpath_s cuando esté disponible.

O si quieres algo portátil, puedes hacer algo como esto

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;

2
No hay _splitpathninguna de las inclusiones en mi máquina.
James Kanze

9
Tengo Visual Studio, y g ++, y Sun CC. ¿Por qué debería usar algo no estándar cuando hay soluciones portátiles perfectamente buenas?
James Kanze

2
@James, la página vinculada dice que está en <stdlib.h>. En cuanto a la portabilidad, ¿quizás pueda enumerar algunos ejemplos de "soluciones portátiles perfectamente buenas"?
Synetech

2
@Synetech La página vinculada describe una extensión de Microsoft, no <stdlib.h>. Y la solución portátil más obvia es boost::filesystem.
James Kanze

3
@James, ¿no tienes _splitpathen stdlib.htu copia de VS? Entonces es posible que desee realizar una instalación de reparación de VS.
Synetech

62

Una posible solución:

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

¡lo más simple es siempre lo mejor!
Jean-François Fabre

60

La tarea es bastante simple ya que el nombre del archivo base es solo la parte de la cadena que comienza en el último delimitador de las carpetas:

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

Si la extensión también debe eliminarse, lo único que debe hacer es encontrar la última .y llevar substra este punto

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

Quizás debería haber una verificación para hacer frente a los archivos que constan únicamente de extensiones (es decir .bashrc...)

Si divide esto en funciones separadas, puede reutilizar las tareas individuales:

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

El código está diseñado para poder usarlo con diferentes std::basic_stringinstancias (es decir, std::string& std::wstring...)

La desventaja de la plantilla es el requisito de especificar el parámetro de plantilla si const char *se pasa a las funciones.

Entonces podrías:

A) Use solo en std::stringlugar de crear una plantilla del código

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

B) Proporcione la función de envoltura usando std::string(como intermedios que probablemente estarán en línea / optimizados)

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

C) Especifique el parámetro de plantilla al llamar con const char *.

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

Resultado

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

Huellas dactilares

MyFile

En este caso de uso, todo está bien (y la pregunta original está respondida), pero el eliminador de extensiones no es perfecto; fallará si pasamos algo como "/home/user/my.dir/myfile"
avtomaton

@avtomaton La función de eliminación de extensiones debe usarse en un nombre de archivo, no en una ruta. ( base_name
Solicítelo

Lo entiendo (es por eso que escribí que la pregunta original está respondida y en este caso de uso todo está bien). Solo quería señalar este problema para alguien que intente usar estos fragmentos.
avtomaton

Muy bonita explicación. Mejora la comprensión estructural del problema. Gracias
hell_ical_vortex

38

La solución más simple es usar algo como boost::filesystem. Si por alguna razón esta no es una opción ...

Hacer esto correctamente requerirá algún código dependiente del sistema: en Windows, '\\'o '/'puede ser un separador de ruta; bajo Unix, solo '/'funciona, y bajo otros sistemas, quién sabe. La solución obvia sería algo como:

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

, MatchPathSeparatordefiniéndose en un encabezado dependiente del sistema como:

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

para Unix, o:

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

para Windows (o algo aún diferente para algún otro sistema desconocido).

EDITAR: Me perdí el hecho de que él también quería suprimir la extensión. Por eso, más de lo mismo:

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

El código es un poco más complejo, porque en este caso, la base del iterador inverso está en el lado equivocado de donde queremos cortar. (Recuerde que la base de un iterador inverso está detrás del carácter al que apunta el iterador). E incluso esto es un poco dudoso: no me gusta el hecho de que pueda devolver una cadena vacía, por ejemplo. (Si el único '.'es el primer carácter del nombre de archivo, yo diría que debería devolver el nombre de archivo completo. Esto requeriría un poco de código adicional para detectar el caso especial.)}


9
¿Qué tal usar en string::find_last_oflugar de manipular iteradores inversos?
Luc Touraille

@LucTouraille ¿Por qué aprender dos formas de hacer las cosas cuando una va a hacer? Necesitaría los iteradores inversos para cualquier contenedor excepto string, por lo que debe aprenderlos de todos modos. Y habiéndolos aprendido, no hay razón para molestarse en aprender toda la interfaz hinchada std::string.
James Kanze

Nota: El encabezado <filesystem> se envía con Visual Studio 2015 y versiones posteriores, por lo que no tiene que agregar una dependencia en boost para usarlo.
IInspectable

15

También puede utilizar las API de ruta de shell PathFindFileName, PathRemoveExtension. Probablemente sea peor que _splitpath para este problema en particular, pero esas API son muy útiles para todo tipo de trabajos de análisis de rutas y tienen en cuenta las rutas UNC, barras diagonales y otras cosas raras.

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

El inconveniente es que tienes que vincular a shlwapi.lib, pero no estoy muy seguro de por qué eso es un inconveniente.


Mi solución preferida para obtener un nombre de archivo de una ruta.
Andreas

15

Si puedes usar boost,

#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();

Esto es todo.

Te recomiendo que uses la biblioteca boost. Boost le brinda muchas comodidades cuando trabaja con C ++. Es compatible con casi todas las plataformas. Si usa Ubuntu, puede instalar la biblioteca boost en una sola línea sudo apt-get install libboost-all-dev(ref. ¿Cómo instalar boost en Ubuntu? )


14

La forma más sencilla en C ++ 17 es:

utilice #include <filesystem>y filename()para el nombre de archivo con extensión y stem()sin extensión.

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

salida:

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

Referencia: cppreference


ya no está en "experimental"
Vit

13

Función:

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

Pruebas:

#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

Desde C ++ Docs - string :: 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;
}

Salidas:

Splitting: /usr/bin/man
 path: /usr/bin
 file: man
Splitting: c:\windows\winhelp.exe
 path: c:\windows
 file: winhelp.exe

No olvide (y maneje) que find_last_ofregresa string::npossi no se encontró nada.
congusbongus

@congusbongus Es cierto, pero no tiene sentido dividir la ruta del archivo cuando es solo un nombre de archivo (sin ruta) :)
jave.web

@ jave.web Tiene sentido y DEBE manejar los retornos 'string :: npos'. La implementación de una función para esto debería poder manejar diferentes entradas, incluido "solo nombre de archivo". De lo contrario, será inútil si tiene errores en la implementación real.
winux

@winux Esto considera PATHS ya válidas ... Si no confía en la entrada, debe, por supuesto, validar la ruta primero.
jave.web

@winux De todos modos,string::npos no es necesario realizar la comprobación debido a la forma en que string::substrse implementan. a) string::npos se pasa como "longitud" => substrtiene un comportamiento documentado de leer todo hasta el final. b) substrse le da " string::npos + 1" y no tiene longitud: string::nposse documenta que tiene un valor de -1, por lo que se evalúa como 0=> inicio de la cadena y el valor predeterminado de las longitudes substres npos=> también funciona en "solo nombre de archivo" cplusplus.com/reference / string / string / substr cplusplus.com/reference/string/string/npos
jave.web

5

Variante de C ++ 11 (inspirada en la versión de James Kanze) con inicialización uniforme y lambda en línea anónimo.

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

Sin embargo, no elimina la extensión del archivo.


Breve y dulce, aunque solo funciona con rutas que no sean de Windows.
Volomike

siempre puede cambiar lambda return para return c == '/' || c == '\\';que funcione en Windows
ziomq1991

Para manejar rutas como "", "///" y "dir1 / dir2 /", agregue el siguiente código antes de la declaración de retorno anterior (cf. 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

La boost filesystembiblioteca también está disponible como experimental/filesystembiblioteca y se fusionó con ISO C ++ para C ++ 17. Puedes usarlo así:

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

namespace fs = std::experimental::filesystem;

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

Salida:

"bar.txt"

También funciona para std::stringobjetos.


4

esto es lo único que finalmente funcionó para mí:

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

más o menos lo que sugirió Skrymsli pero no funciona con wchar_t *, VS Enterprise 2015

_splitpath también funcionó, pero no me gusta tener que adivinar cuántos caracteres char [?] voy a necesitar; algunas personas probablemente necesitan este control, supongo.

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

No creo que se necesitara ninguna inclusión para _splitpath. No se necesitaron bibliotecas externas (como boost) para ninguna de estas soluciones.


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

3

Lo haría por ...

Busque hacia atrás desde el final de la cadena hasta que encuentre la primera barra invertida / barra inclinada hacia adelante.

Luego busque hacia atrás nuevamente desde el final de la cadena hasta que encuentre el primer punto (.)

Luego tiene el inicio y el final del nombre del archivo.

Simples ...


Lo cual no funciona para ningún sistema que conozca. (El único sistema que acepta '\\'como separador de ruta también lo usa '/', por lo que debe hacer coincidir cualquiera de los dos). Y no estoy seguro de lo que estaría esperando.
James Kanze

Bien, modifíquelo para que coincida con cualquiera de los dos, no hay problema. Y esperando el primer punto (.)
TomP89

Aún tienes que encontrar el último punto, no el primero. (¡Los iteradores inversos son tus amigos!)
James Kanze

Ah, sí, buen punto. Entonces, para un file.ext.ext, entonces querría extraer file.ext, ¿no es así? :)
TomP89

Presumiblemente. Esa es la convención habitual, en cualquier caso: my.source.cppse compila en my.source.obj, por ejemplo (con la extensión .cppreemplazada por .obj).
James Kanze

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

La variable m_szFileName contiene el nombre de archivo.


3
wow - eso es mucho código para "obtener el nombre del archivo" de la ruta ... :)
Nim

4
@Nim Mi impresión también. En mi propio código, uso una sola línea: boost::filesystem::path( path ).filename().
James Kanze

Tengo una clase CFileInfo que tiene ese código. Dejé el código aquí porque está probado y no quería arriesgar nada ... Podrías usar unas 5 líneas de código de este ejemplo.
Lucian


2

Esto también debería funcionar:

// 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("."));
}

Si puede usarlo, Qt proporciona QString (con split, trim, etc.), QFile, QPath, QFileInfo, etc. para manipular archivos, nombres de archivos y directorios. Y, por supuesto, también es una plataforma cruzada.


4
Por el bien de los futuros lectores de su código, utilice variables temporales con nombres significativos en lugar de meter todo en una sola línea de código (y mientras lo hace, encapsule todo esto en una función getFilenameo algo así).
Luc Touraille

editado. Pero el punto era hacerlo breve, ya que ya se han dado varias respuestas prácticas.
typedef

1
Creo que es un error. ¿No debería reemplazar la última parte: "strPath.size () - strPath.find_last_of (". ")" Por "strPath.find_last_of (". ") - iLastSeparator"
taktak004

@ taktak004 tiene razón, debería ser `return strPath.substr ((iLastSeparator = strPath.find_last_of (" / "))! = std :: string :: npos? iLastSeparator + 1: 0, strPath.find_last_of (". " ) - iLastSeparator); `
phenmod

2

Puede usar el sistema de archivos std :: para hacerlo bastante bien:

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

fs::path myFilePath("C:\\MyDirectory\\MyFile.bat");
fs::path filename = myFilePath.stem();

0

Durante mucho tiempo estuve buscando una función capaz de descomponer correctamente la ruta del archivo. Para mí, este código funciona perfectamente tanto para Linux como para 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);
}

Los resultados de ejemplo son:

[]
  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:  ''

Espero que esto también te ayude :)


0

shlwapi.lib/dllutiliza el HKCUsubárbol del registro internamente.

Es mejor no vincularlo shlwapi.libsi está creando una biblioteca o si el producto no tiene una interfaz de usuario. Si está escribiendo una biblioteca, su código se puede usar en cualquier proyecto, incluidos aquellos que no tienen IU.

Si está escribiendo código que se ejecuta cuando un usuario no está conectado (por ejemplo, servicio [u otro] configurado para iniciarse en el inicio o inicio), entonces no hay HKCU. Por último, shlwapi son funciones de liquidación; y como resultado alto en la lista para desaprobar en versiones posteriores de Windows.


0

Una solución de expresiones regulares lenta pero sencilla:

    std::string file = std::regex_replace(path, std::regex("(.*\\/)|(\\..*)"), "");
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.