Obtener la ruta de los padres -- ++ campo con algorithm campo con strings camp codereview Relacionados El problema

Get parent path


4
vote

problema

Español

Estoy tratando de escribir una función que haría lo que haría un 9988776665544330 . Básicamente, consigue a los padres del camino dado. EG:

  C: --> C: C:Usersxxx --> C:Users test1 est2 est4 --> test1 est2 /var/etc/jpt --> /var/etc   

He probado esto en Windows y Linux. Aquí están la lista de comentarios que tengo.

Estoy declarando forward_slash y backward_slash para que funcione tanto en Win como en Linux. Uno podría preguntar, ¿qué pasa si hay otro delimémetro de la ruta? Por ahora, vamos a apegarse a estos dos deliméteres. Si no encuentro ninguno de los dos delimitadores, acabo de devolver el camino en sí mismo.

I Bucle sobre el dir_path Tratando de encontrar el primer y segundo delimitador.

  • Tengo que hacer -1 AQUÍ int index = dir_path.size()-1; Para evitar el error obligado.

  • Si no hay delimitador que se encuentra desde la primera posición delimitador (usando 9988776655544336 ) devuelvo la subcatación de 0 a primera posición delimitador + 1. Tengo que +1 aquí porque el bucle ya movido el índice por -1.

  • Si hay algo entre los dos delimitadores consecutivos, acabo de devolver la substa de 0 a segunda posición delimitador.

  • Tengo que hacer el if (second_delimeter_pos == std::string::npos) primero.

El siguiente código también tiene rutas de prueba.

  #include <iostream> #include <string> #include <vector>   std::vector<std::string> generatePaths() {     std::vector<std::string> paths;      paths.emplace_back("C:\Users\xxxx\\");     paths.emplace_back("C:\");     paths.emplace_back("C:");     paths.emplace_back("C:\\");     paths.emplace_back("C://");     paths.emplace_back("C:/");     paths.emplace_back("test\test1\tmp2");     paths.emplace_back("C:\Users\xxxxx\projects\\\play_ground\\\");     paths.emplace_back("C:/Users/xxxxxx/projects/////play_ground////");          return paths; }  std::string getParentDir(const std::string& dir_path) {      std::string forward_slash = "/";     std::string backward_slash = "\";         std::string delimiter;      if (dir_path.find(forward_slash) != std::string::npos) {         delimiter = forward_slash;     }     else if (dir_path.find(backward_slash) != std::string::npos) {         delimiter = backward_slash;     }     else {         return dir_path;     }     std::string parent_path;      for (int index = dir_path.size()-1; index > 0 ; --index) {                  int first_delimeter_pos = index;         size_t second_delimeter_pos = (int)dir_path.find_last_of(delimiter, first_delimeter_pos);         int diff = first_delimeter_pos - second_delimeter_pos;                  if (second_delimeter_pos == std::string::npos) {             parent_path = dir_path.substr(0, first_delimeter_pos+1);             break;         }         if (diff > 1) {             parent_path = dir_path.substr(0, second_delimeter_pos);             break;         }         index -= diff;     }      return parent_path; } int main() {     std::vector<std::string> test_paths = generatePaths();     for (int i = 0; i < test_paths.size(); ++i) {         std::string my_dir = test_paths[i];         std::string parent_dir = getParentDir(my_dir);          std::cout << "dir =  " << my_dir << " :: parent dir = " << parent_dir << std::endl;      } }   

Cualquier sugerencia, mejoras y escollos en el diseño y algoritmo es muy apreciado.

Original en ingles

I am trying to write a function that would do what a cd .. would do. Basically get the parent of the given path. eg:

C:\ --> C:\ C:\Users\xxx --> C:\Users test1\test2\test4 --> test1\test2\ /var/etc/jpt --> /var/etc 

I have tested this in windows and linux. Here are the list of comments I have.

I am declaring forward_slash and backward_slash so that it would work on both win and linux. One might ask, what if there are other path delimeter? For now, lets just stick to these two delimeters. If I do not find any of the two delimiters, I just return the path itself.

I loop over the dir_path trying to find the first and second delimiter.

  • I have to do -1 here int index = dir_path.size()-1; to avoid out of bound error.

  • If there is no delimiter found from first delimiter position (using find_last_of) then I return sub string from 0 to first delimiter position + 1. I have to +1 here because the for loop already moved the index by -1.

  • If there is any thing in between the two consecutive delimiter, I just return the sub string from 0 to second delimiter position.

  • I have to do the if (second_delimeter_pos == std::string::npos) first.

The below code also has test paths.

#include <iostream> #include <string> #include <vector>   std::vector<std::string> generatePaths() {     std::vector<std::string> paths;      paths.emplace_back("C:\\Users\\xxxx\\\\");     paths.emplace_back("C:\\");     paths.emplace_back("C:");     paths.emplace_back("C:\\\\");     paths.emplace_back("C://");     paths.emplace_back("C:/");     paths.emplace_back("test\\test1\\tmp2");     paths.emplace_back("C:\\Users\\xxxxx\\projects\\\\\\play_ground\\\\\\");     paths.emplace_back("C:/Users/xxxxxx/projects/////play_ground////");          return paths; }  std::string getParentDir(const std::string& dir_path) {      std::string forward_slash = "/";     std::string backward_slash = "\\";         std::string delimiter;      if (dir_path.find(forward_slash) != std::string::npos) {         delimiter = forward_slash;     }     else if (dir_path.find(backward_slash) != std::string::npos) {         delimiter = backward_slash;     }     else {         return dir_path;     }     std::string parent_path;      for (int index = dir_path.size()-1; index > 0 ; --index) {                  int first_delimeter_pos = index;         size_t second_delimeter_pos = (int)dir_path.find_last_of(delimiter, first_delimeter_pos);         int diff = first_delimeter_pos - second_delimeter_pos;                  if (second_delimeter_pos == std::string::npos) {             parent_path = dir_path.substr(0, first_delimeter_pos+1);             break;         }         if (diff > 1) {             parent_path = dir_path.substr(0, second_delimeter_pos);             break;         }         index -= diff;     }      return parent_path; } int main() {     std::vector<std::string> test_paths = generatePaths();     for (int i = 0; i < test_paths.size(); ++i) {         std::string my_dir = test_paths[i];         std::string parent_dir = getParentDir(my_dir);          std::cout << "dir =  " << my_dir << " :: parent dir = " << parent_dir << std::endl;      } } 

Any suggestion, improvements and pitfall on design and algorithm is highly appreciated.

        
 
 

Lista de respuestas

5
 
vote
vote
La mejor respuesta
 

Si puede usar C ++ 17 puede usar el sistema de archivos STL, este encabezado contiene facultades para realizar operaciones en rutas y archivos y haría que su código sea más sencillo, por ejemplo, el delimitador se puede manejar con el std::filesystem::path < / Código> Clase.

De acuerdo con la documentación de std::filesystem::path se puede normalizar siguiendo este algoritmo:

  • Si el camino está vacío, detener (la forma normal de una ruta vacía es una ruta vacía)
  • Reemplace cada separador de directorios (que puede consistir en múltiples barras) con un solo path::preferred_separator .
  • Reemplace cada carácter de slash en el nombre de la raíz con path::preferred_separator .
  • Retire cada punto y cualquier otro separador de directorio.
  • Elimine cada nombre de archivo sin puntos inmediatamente seguido de un separador de directorios y un punto de puntos, junto con cualquier separador de directorio inmediatamente siguiente.
  • Si hay un directorio de root-, elimine todos los puntos de puntos y cualquier separador de directorios inmediatamente siguiéndolos.
  • Si el último nombre de archivo es Dot-Dot, elimine cualquier separador de directorio posterior.
  • Si la ruta está vacía, agregue un punto (forma normal de ./ es.)

Mira aquí para más información

Tamaño de fundición innecesario_t a int
Muelve el resultado de find_last_of a int y asignándolo a un size_t Mientras que el resultado de find_last_of es de tipo size_t .

Prefiero usar ' n' en lugar de std::endl
No hará mucha diferencia en este caso en particular, pero es Es bueno hacerlo un habbit, 9988776655544339 descargará el búfer de salida cada vez que puede ser un golpe de rendimiento. Vea esto para más

Uso del rango basado en el bucle
Debido a que no necesita el índice para otra cosa, sino acceder al artículo en el vector, puede reemplazar:
std::filesystem::path0

con: std::filesystem::path1 donde std::filesystem::path2 será el elemento en índice n del vector.

 

If you can use c++17 you can use the stl filesystem, this header contains faculties for performing operations on paths and files and would make your code simpler, for example the delimiter can be handled with the std::filesystem::path class.

According to the documentation of std::filesystem::path a path can be normalized by following this algorithm:

  • If the path is empty, stop (normal form of an empty path is an empty path)
  • Replace each directory-separator (which may consist of multiple slashes) with a single path::preferred_separator.
  • Replace each slash character in the root-name with path::preferred_separator.
  • Remove each dot and any immediately following directory-separator.
  • Remove each non-dot-dot filename immediately followed by a directory-separator and a dot-dot, along with any immediately following directory-separator.
  • If there is root-directory, remove all dot-dots and any directory-separators immediately following them.
  • If the last filename is dot-dot, remove any trailing directory-separator.
  • If the path is empty, add a dot (normal form of ./ is .)

Look here for more info

Unnecessary cast size_t to int
You cast the result of find_last_of to int and assign it to a size_t this while the result of find_last_of is of type size_t.

Prefer using '\n' instead of std::endl
It won't make a lot of difference in this particular case but it is good to make it an habbit, std::endl will flush the output buffer each time what can be a performance hit. See this for more

Use range based for loop
Because you don't need the index for anything else but accessing the item in the vector you can replace:
for (int i = 0; i < test_paths.size(); ++i)

with: for(auto path : test_paths) where path will then be the item at n index of the vector.

 
 
     
     

Relacionados problema

2  Función para borrar un carácter en una cadena  ( Function to erase a character in a string ) 
void chrrem (char arr[], size_t len, size_t pos) { memmove(arr + pos, arr + (pos + 1), (len - pos) + 1); } Se supone que es simplemente rápido. Borra...

1  Imprima todos los tamaños posibles de subsecuencias de cadena en C  ( Print out all possible sizes of subsequences of string in c ) 
Por ejemplo, dada una cadena "abcdefghijk", quiero que mi función se imprima: a, b, c, d, e, f, g, h, i, j, k. ab, bc, cd, de, ef, fg, gh, hi, ij, jk ab...

3  Implementación más portátil de Tolower ()  ( More portable tolower implementation ) 
Me estoy desafiando a intentar intentar escribir una función que sea tan eficiente, portátil y a prueba de fallas posible. La función es muy simple y solo con...

1  Compruebe si dos cadenas son permutación entre sí  ( Check if two strings are permutation of each other ) 
private String sort(String word) { char[] content = word.toCharArray(); Arrays.sort(content); return new String(content); } private boolea...

6  Las vocales en una cadena están en orden alfabético  ( Vowels in a string are in alphabetical order ) 
Tarea Escriba una implementación que devuelva si un 99887776655544330 tiene vocales (idioma inglés) en orden alfabético (A-Z) o no. Feedback es mi v...

10  Función recursiva que genera las permutaciones de una cadena  ( Recursive function that generates the permutations of a string ) 
Estoy buscando una revisión de mi función recursiva que genere las permutaciones de una cadena. ¿Hay mejores formas de hacer esto? var permutations = []; ...

11  Optimizando el corrector de anagramas Java (comparar 2 cadenas)  ( Optimizing java anagram checker compare 2 strings ) 
Un anagrama es como una mezcla de las letras en una cadena: pots es un anagrama de detener wilma es un anagrama de ilwma Estoy pasando por el ...

18  Invirtiendo una cadena  ( Reversing a string ) 
Tuve esto como una pregunta de entrevista, y el entrevistador señaló esto. Esto es lo que escribí: //C# Syntax here public string Reverse(string s) { c...

8  Conversión de STD :: Chrono :: Time_Point to / from std :: string  ( Converting stdchronotime point to from stdstring ) 
Considere estas funciones que permitan convertir checkOnline.sh4 a / FROM checkOnline.sh5 Con un formato Fecha de fecha ". checkOnline.sh6 con uso:...

9  Convierta una contraseña a una cadena fonética para usuarios finales  ( Convert a password to a phonetic string for end users ) 
Tanto como lo odio, a veces proporcionar contraseñas a las personas debe hacerse electrónicamente. Cuando hago eso, trato de eliminar cualquier ambigüedad que...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos