Remove whitespace excesses from a string

Asked

Viewed 38 times

-2

I need to make a program that reads a text file, copies the information and transfers it to another file, but without the blank lines, without comment code (which starts at "//") and remove excess blank spaces between words. The le_clean_e_saved function does its job, but the clean_space function is returning empty strings, and therefore creating a new empty file. And I don’t know why you’re doing it. Somebody help please.

#include <iostream>
#include <fstream>

using namespace std;

void limpa_espacos(string &str)
{
    int p1= 0; // ponteiro para string de entrada
    int p2= 0; // para string de saida
    string temp; // guarda a string a medida que é limpa
    
    while(str[p1]!='\0') // varre a string ate o fim
    {
        temp[p2]= str[p1]; // copia uma posicao da string de entrada para temp
        
        if(str[p1]==' ') // se essa posicao é um espaco
        {
            while(str[p1+1]!='\0' && str[p1+1]==' ') // enquanto nao chegar no fim da string e as 
                                                     // proximas posicoes continuam sendo espacos
            {
                p1++; // vai empurrando o ponteiro da string de entrada
            }
        }
        
        // senão, apenas incrementa ambos os ponteiros, ou incrementa de qualquer forma
        p1++;
        p2++;
    }
    
    temp[p2]= '\0'; // fecha a string
    str= temp;
}

void le_limpa_e_salva (ifstream &lod, ofstream &sav, string st)
{
    // enquanto tiver uma linha no arquivo com caracteres, esse "while" vai rodar
    while (getline(lod, st)) // faz leitura de uma linha do arquivo
    {
        if(!st.empty() && (st[0] != '/' && st[1] != '/')) // se a linha nao estiver vazia
        {
            cout << "\nantes de limpar espacos: " << st << "\n";
            limpa_espacos(st);
            cout << "\ndepois de limpar espacos: " << st << "\n";
            sav << st << "\n"; // grava essa linha no novo arquivo e pula para linha de baixo       
        }               
    }           
    lod.close();
    sav.close();        
    cout << "\n\nArquivo copiado com sucesso!\n\n";
}

int main()
{
    ifstream load;
    ofstream save;
    string str, apaga;
    
    // arq_orig: guarda o nome do arquivo digitado pelo usuario (arquivo fonte)
    // arq_dest: guarda o nome do arquivo digitado pelo usuario (arquivo de destino)
    char arq_orig[1023], arq_dest[1023]; 

    cout << "Digite o nome do arquivo a ser copiado, com sua extensao.\n";
    cout << "Digite: ";

    // muito melhor que colocar no codigo, o local do arquivo a ser lido
    // e o local do novo arquivo a ser criado, pois para cada execucao
    // em computador diferente, esse trecho do codigo deveria ser alterado.
    // Alem disso, ha diferenca de formatacao desse caminho para Windows e Linux.
    
    gets(arq_orig); // "pega" o nome digitado pelo usuario

    load.open(arq_orig); // lê o arquivo com esse nome

    if(load) // verificacao de erro
    {
        cout << "Digite o nome do arquivo que recebera o texto copiado, com sua extensao.\n";
        cout << "Digite: ";
        
        gets(arq_dest);
    
        save.open(arq_dest);
    
        if (save)
        {
            le_limpa_e_salva (load, save, str);
        
            load.close();
            save.close();
        }
        else
        {
            cout << "\n\nFalha ao criar arquivo de destino! Fechando programa.\n\n";
        }                           
    }
    else
    {
        cout << "\n\nFalha ao abrir arquivo fonte! Fechando programa.\n\n";
    }

    return 0;   
}

1 answer

0

Hello!

You have written something like C and not C++. To copy the values to the output string use '+' which is reset to strings and does what you want.

       temp[p2]= str[p1]; // C, mas temp deve ter sido alocado antes

In C there should already be memory allocated to the new string and you can copy it. In C++ use

       temp += str[p1]; // C++, aloca conforme preciso

But consider this function

string      trim(string& str)
{
    string nova{};
    char* p = &str[0];
    char branco = 0;
    while( *p!=0)
    {
        if ( *p == ' ')
            if ( branco == 0 )
            {
                branco = 1;
                nova += *p;
            }
            else
                ;
        else
        {
            branco = 0;
            nova += *p;
        }
        p++;
    };  // while()
    return nova;   
}

which does what you want and is more flexible because it returns a string and can use in an expression like

    const string teste[] =
    { 
        "  teste    t e s    te  ",
        "azul",
        "  azul",
        "azul  ",
        " azul",
        "azul "
    };

    for ( auto str : teste )
        std::cout << "\nAntes: '" << str <<
            "' Depois: '" << trim(str) << "'\n";

exit

PS C:\src\CPP\flt> g++ -o tst -Wall -std=c++17 tle.cpp
PS C:\src\CPP\flt> ./tst

Antes: '  teste    t e s    te  ' Depois: ' teste t e s te '

Antes: 'azul' Depois: 'azul'

Antes: '  azul' Depois: ' azul'

Antes: 'azul  ' Depois: 'azul '

Antes: ' azul' Depois: ' azul'

Antes: 'azul ' Depois: 'azul '
PS C:\src\CPP\flt>

of this example

#include <iostream>
using namespace std;

string      trim(string& str);

int main(void)
{
    const string teste[] =
    { 
        "  teste    t e s    te  ",
        "azul",
        "  azul",
        "azul  ",
        " azul",
        "azul "
    };

    for ( auto str : teste )
        std::cout << "\nAntes: '" << str <<
            "' Depois: '" << trim(str) << "'\n";

    return 0;   
}


string      trim(string& str)
{
    string nova{};
    char* p = &str[0];
    char branco = 0;
    while( *p!=0)
    {
        if ( *p == ' ')
            if ( branco == 0 )
            {
                branco = 1;
                nova += *p;
            }
            else
                ;
        else
        {
            branco = 0;
            nova += *p;
        }
        p++;
    };  // while()
    return nova;   
}
// main.cpp

Alternative: use a state machine

Because your program is a filter and passes through the input only once, a state machine is something much simpler. And read the file as a sequence of letters. Here are the states:

  • reading a value
  • after reading a space
  • after reading a /
  • after reading an additional space
  • after reading a second /
  • read a \n
  • end of file

You don’t need functions for anything if you use this. If you need to type and I show an example

Browser other questions tagged

You are not signed in. Login or sign up in order to post.