Created
April 4, 2023 08:50
-
-
Save pcolladosoto/ccc0d99a8416827147b28b13873e3351 to your computer and use it in GitHub Desktop.
Procesador de vectores separados por espacios
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
0 0.5 | |
1 10 | |
2 20.5 | |
3 30 | |
4 40.5 | |
5 50 | |
6 60.5 | |
7 70 | |
8 80.5 | |
9 90 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Vamos a mostrar algún mensaje por pantalla. | |
* Más información -> https://en.cppreference.com/w/cpp/header/iostream | |
*/ | |
#include <iostream> | |
/* Tenemos que poder abrir archivos. Esta cabecera define `std::fstream`. | |
* Más información -> https://en.cppreference.com/w/cpp/header/basic_fstream | |
*/ | |
#include <fstream> | |
/* Vamos a usar expresiones regulares para sacar los datos. | |
* Para jugar con ello https://regex101.com está genial. | |
* Más información -> https://en.cppreference.com/w/cpp/header/regex | |
*/ | |
#include <regex> | |
/* Vamos a usar muchas cadenas (i.e. strings). | |
* Más información -> https://en.cppreference.com/w/cpp/header/string | |
*/ | |
#include <string> | |
/* En vez de la clase `mivector` vamos a usar la clase estándar `std::vector`. | |
* La idea es prácticamente la misma, pero al ser estándar este programa funcionará | |
* con mucha más facilidad en otros equipos y situaciones. En el siguiente enlace tienes | |
* información para ponerte a funcionar con vectores: https://www.programiz.com/cpp-programming/vectors | |
* Más información -> https://en.cppreference.com/w/cpp/header/vector | |
*/ | |
#include <vector> | |
/* También vamos a hacer una versión con nuestro `mivectort`. Recuerda que debes | |
* poder importarlo, para lo que lo deberás tener copiado en `/usr/local/include`. | |
* Entiendo que ya estará ahí con lo que vimos en clase :P | |
*/ | |
#include <mivectort> | |
/* | |
* Este objeto contiene la expresión regular que extrae los números | |
* de cada línea del archivo de entrada. En el siguiente enlace tienes | |
* una versión con la que puedes jugar: https://regex101.com/r/WO5A8m/2 | |
*/ | |
const std::regex lineRegex("([^\\s]+)\\s+([^\\s]+)"); | |
/* | |
* Esta función recibe el nombre del archivo que queremos abrir para | |
* abrirlo, leer todos los datos, y devolver un vector de vectores de floats. | |
*/ | |
std::vector<std::vector<float>> parse_file(std::string fname) { | |
// Definimos un flujo al que conectar el archivo. | |
std::fstream infile; | |
/* Vamos a abrir el archivo. | |
* open() -> https://en.cppreference.com/w/cpp/io/basic_fstream/open | |
* std::ios::openmode -> https://en.cppreference.com/w/cpp/io/ios_base/openmode | |
*/ | |
infile.open(fname, std::ios::in); | |
// En este vector iremos almacenando los datos de cada linea que leamos. | |
std::vector<std::vector<float>> data; | |
// En este vector iremos almacenando los datos de cada línea. | |
std::vector<float> lineData; | |
// En esta cadena iremos guardando cada línea que vayamos leyendo. | |
std::string line; | |
// Este objeto irá almacenando los números que vayamos encontrando. | |
std::smatch dataMatch; | |
/* | |
* La función `std::getline` irá leyendo el archivo `infile` línea por línea. Cada | |
* vez que lea una linea la almacenará en `line` para que la podamos procesar. Cuando | |
* se haya leído todo el archivo, `std::getline` provoca que el bucle se termine. | |
*/ | |
while (std::getline(infile, line)) { | |
// Veamos en qué línea estamos... | |
// std::cout << "Procesando la linea: " << line << std::endl; | |
// Vamos a aplicar la expresión regular a la linea. | |
std::regex_match(line, dataMatch, lineRegex); | |
// Veamos si hemos capturado dos números. El «match» contiene | |
// los dos números y otra captura que es la línea entera; de ahí | |
// la comprobación con · en vez de con 2. | |
if (dataMatch.size() != 3) { | |
std::cout << "\tNo se ha podido procesar esta línea...\n"; | |
// A por la siguiente línea... | |
continue; | |
} | |
/* Añadimos la primera componente al final del vector en el que almacenamos | |
* los datos de la línea. La función `std::stof` convierte la primera componente | |
* en un `float` (de ahí la f). Hay otras versiones para double y demás. En | |
* https://en.cppreference.com/w/cpp/string/basic_string/stof hay más información. | |
*/ | |
lineData.push_back(std::stof(dataMatch[1])); | |
// Hacemos lo mismo con la segunda componente; | |
lineData.push_back(std::stof(dataMatch[2])); | |
// Añadimos el vector intermedio al general en el que tenemos todos los datos. | |
data.push_back(lineData); | |
// Limpiamos el vector que usamos para cada línea para la siguiente iteración. | |
lineData.clear(); | |
} | |
// Y devolvemos los datos ya guardados. | |
return data; | |
} | |
/* | |
* Esta función es equivalente a la anterior, pero hace uso de nuestra clase `mivectort`. | |
*/ | |
mivector<mivector<float>> parse_file_mv(std::string fname) { | |
std::fstream infile; | |
infile.open(fname, std::ios::in); | |
mivector<mivector<float>> data; | |
// mivector<float> lineData; | |
std::string line; | |
std::smatch dataMatch; | |
while (std::getline(infile, line)) { | |
// std::cout << "Procesando la linea: " << line << std::endl; | |
std::regex_match(line, dataMatch, lineRegex); | |
if (dataMatch.size() != 3) { | |
std::cout << "\tNo se ha podido procesar esta línea...\n"; | |
continue; | |
} | |
data.append(mivector<float>({std::stof(dataMatch[1]), std::stof(dataMatch[2])})); | |
} | |
return data; | |
} | |
/* | |
* Y ahora con `mivector` y usando simplemente la el operador de extracción `>>`. | |
*/ | |
mivector<mivector<float>> parse_file_eo(std::string fname) { | |
std::fstream infile; | |
infile.open(fname, std::ios::in); | |
mivector<mivector<float>> data; | |
// Iremos almacenando los datos en este vector temporal con dos componentes. | |
mivector<float> currComponents(2); | |
// Tenemos que llevar la cuenta de componentes: cada 2 debemos | |
// insertar una file nueva. | |
int nComponents = 0; | |
// Aquí iremos guardando el valor de cada componente. | |
float tmpComponent; | |
// La gracia de todo esto es que el operador de extracción por defecto | |
// para en cualquier espacio en blanco. Podemos usar eso en nuestro beneficio. | |
// Como siempre, cuando se agote el archivo (i.e. `infile`) el bucle se para. | |
while (infile >> tmpComponent) { | |
// Aquí usamos mucho el operador módulo, que devuelve el resto de la | |
// división entera. Así, cuando tengamos un número par de componentes | |
// sobreescribimos la primera componente del vector de las líneas y cuando | |
// sea impar sobreescribimos la segunda. | |
currComponents[nComponents % 2] = tmpComponent; | |
// Actualizamos la cuenta para que el operador módulo vaya funcionando. La | |
// actualización viene después de la operación anterior para que las | |
// cosas cuadren. | |
nComponents++; | |
// Cada dos componentes tenemos que guardar una nueva entrada. | |
if (nComponents % 2 == 0) | |
data.append(currComponents); | |
} | |
// ¡Y listo! | |
return data; | |
} | |
/* Para compilarlo podemos usar lo de siempre: | |
* $ g++ -std=c++11 -o pvector.ex vector_parser.cpp | |
* | |
* Para ejecutarlo podemos usar: | |
* $ ./pvector.ex | |
*/ | |
int main() { | |
std::cout << "Vamos a procesar el archivo `vector.txt`...\n"; | |
// Usando vectores de la librería estándar. | |
std::vector<std::vector<float>> parsedData = parse_file("vector.txt"); | |
std::cout << "Resultado del procesado con `parse_file()`:\n"; | |
// Vamos a imprimir el vector que nos ha quedado. | |
for (const std::vector<float>& row : parsedData) { | |
std::cout << "\t( "; | |
for (const float& component : row) | |
std::cout << component << " "; | |
std::cout << ")\n"; | |
} | |
// Usando `mivector` con expresiones regulares. | |
mivector<mivector<float>> parsedDataMv = parse_file_mv("vector.txt"); | |
std::cout << "Resultado del procesado con `parse_file_mv()`:\n"; | |
for (int i = 0; i < parsedDataMv.dimension(); i++) | |
std::cout << "\t(" << parsedDataMv[i][0] << ", " << parsedDataMv[i][1] << ")\n"; | |
// Usando `mivector` con el operador de extracción. | |
mivector<mivector<float>> parsedDataEo = parse_file_eo("vector.txt"); | |
std::cout << "Resultado del procesado con `parse_file_eo()`:\n"; | |
for (int i = 0; i < parsedDataEo.dimension(); i++) | |
std::cout << "\t(" << parsedDataEo[i][0] << ", " << parsedDataEo[i][1] << ")\n"; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment