Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

lekcja 28 zadanie - ilość pętli

Ostatnio zmodyfikowano 2019-03-14 23:24
Autor Wiadomość
Brys
Temat założony przez niniejszego użytkownika
lekcja 28 zadanie - ilość pętli
» 2019-03-12 21:03:22
Cześć
wpadłem na takie rozwiązanie zadania domowego z lekcji 28
C/C++
#include <iostream>
#include <string>
using namespace std;

std::string konwertuj( std::string sTekst )
{
    size_t miejsce;
    do
    {
        if( sTekst.find( "<b>", 0 ) != string::npos )
        {
            miejsce = sTekst.find( "<b>" );
            sTekst.insert( miejsce, "[b]" );
            sTekst.erase(( miejsce + 3 ), 3 );
        }
    } while( sTekst.find( "<b>" ) != string::npos );
   
    do
    {
        if( sTekst.find( "</b>", 0 ) != string::npos )
        {
            miejsce = sTekst.find( "</b>" );
            sTekst.insert( miejsce, "[/b]" );
            sTekst.erase(( miejsce + 4 ), 4 );
        }
    } while( sTekst.find( "</b>" ) != string::npos );
   
    do
    {
        if( sTekst.find( "  ", 0 ) != string::npos )
        {
            miejsce = sTekst.find( "  " );
            sTekst.insert( miejsce, " " );
            sTekst.erase(( miejsce + 1 ), 2 );
        }
    } while( sTekst.find( "  " ) != string::npos );
   
    return sTekst;
   
}
int main()
{
    std::cout << konwertuj( "<b>to jest </b> testowy       napis     <b>:)" ) << std::endl;
    std::cout << konwertuj( "  s       a         m      e         sp    a   c j    e" ) << std::endl;
    std::cout << konwertuj( "<<B><//b><i></i>" ) << std::endl;
    return 0;
}
Po uruchomieniu program zwraca takie dane jakie miały być zwracane według treści zadania, więc z jego działaniem nie widzę problemu, ale przeglądając forum znalazłem jeden temat, w którym ktoś sugerował, że do rozwiązania tego zadania wystarczy tylko jedna pętla, a ja niestety nie wiem jak to ma działać z jedną pętlą. Mógłby ktoś doradzić jak można skrócić/zoptymalizować ten kod?
P-174176
pekfos
» 2019-03-12 21:38:21
Zamiast pisać 3 takie same pętle, napisz dodatkową funkcję i wywołaj ją 3 razy.

Mógłby ktoś doradzić jak można skrócić/zoptymalizować ten kod?
Zoptymalizować? Zabawne że wspominasz..
C/C++
do
{
    if( sTekst.find( "<b>", 0 ) != string::npos ) // wyszukiwanie
    {
        miejsce = sTekst.find( "<b>" ); // wyszukiwanie
        sTekst.insert( miejsce, "[b]" );
        sTekst.erase(( miejsce + 3 ), 3 );
    }
} while( sTekst.find( "<b>" ) != string::npos ); // wyszukiwanie

Nie ma powodu, dla którego miałbyś szukać każdego wystąpienia po 3 razy. Nie ma też powodu, dla którego wyszukiwanie miałoby się za każdym razem zaczynać od początku napisu.

Pod względem wydajności i tak będzie tu wiele do poprawienia. Choćby to, że insert() i erase() są dopuszczalne do takiego zastosowania tylko dlatego, że to zadanie do lekcji, która omawia te metody.
P-174177
Brys
Temat założony przez niniejszego użytkownika
» 2019-03-13 20:18:12
Trochę zmieniłem, już nie wyszukuje po 3 razy od zera, ale nie wiem jak zmniejszyć ilość pętli
C/C++
std::string konwertuj( std::string sTekst )
{
    size_t miejsce = 0;
    do
    {
        miejsce = sTekst.find( "<b>", miejsce );
        if( miejsce != string::npos )
        {
            sTekst.insert( miejsce, "[b]" );
            sTekst.erase(( miejsce + 3 ), 3 );
        }
    } while( miejsce != string::npos );
   
    miejsce = 0;
    do
    {
        miejsce = sTekst.find( "</b>", miejsce );
        if( miejsce != string::npos )
        {
            sTekst.insert( miejsce, "[/b]" );
            sTekst.erase(( miejsce + 4 ), 4 );
        }
    } while( miejsce != string::npos );
   
    miejsce = 0;
    do
    {
        miejsce = sTekst.find( "  ", miejsce );
        if( miejsce != string::npos )
        {
            sTekst.insert( miejsce, " " );
            sTekst.erase(( miejsce + 1 ), 2 );
        }
    } while( miejsce != string::npos );
   
    return sTekst;
   
}
P-174184
jankowalski25
» 2019-03-13 22:34:14
Jak chcesz mieć mniej pętli, to idź znak po znaku. Zauważ, że wynik końcowy może być co najwyżej takiej samej długości, a często będzie krótszy. A skoro tak, to wystarczy zapamiętywać dwie pozycje: jedną do odczytu znaku, a drugą do zapisu. Na końcu wystarczy ewentualnie uciąć resztę we właściwym miejscu. Wspomniany algorytm jest już opisany na forum, więc gdyby samodzielne próby zmierzenia się z problemem nie pomogły, to poszukaj podobnego tematu na forum (nie chcę dawać teraz linka, zawsze lepiej samemu dojść do właściwego rozwiązania niż je zobaczyć od razu).
P-174186
Brys
Temat założony przez niniejszego użytkownika
» 2019-03-14 18:23:55
Znalazłem na forum takie rozwiązanie do usuwania spacji
C/C++
int j = 0;
int ileZnakow = sTekst.size();
for( int i = 0; i < ileZnakow; i++ )
{
    if(( sTekst[ i ] != ' ' ) ||( sTekst[ i + 1 ] != ' ' ) )
    {
        sTekst[ j ] = sTekst[ i ];
        j++;
    }
}
sTekst.resize( j );
przeanalizowałem je i rozumiem jego działanie.
Wpadłem na pomysł, czytając też o .replace(), żeby wykorzystać ten kod przy zmianie w zadaniu znaczników <'b'> i zrobiłem takie coś
C/C++
int j = 0;
int ileZnakow = sTekst.size();
for( int i = 0; i < ileZnakow; i++ )
{
    if(( sTekst[ i ] == '<' ) &&( sTekst[ i + 1 ] == 'b' ) &&( sTekst[ i = 2 ] == '>' ) )
    {
        sTekst.replace( i, 3, "[b]" );
       
    }
}
ale to nie działa, program odpala się ale nic się nie dzieje
P-174189
jankowalski25
» 2019-03-14 19:37:22
Widzę, że już przeczytałeś temat 3.28 Usuwanie spacji, więc teraz pozostaje jedynie kwestia właściwej rozbudowy wspomnianego algorytmu tak, aby uwzględniał zamianę znaczników.

sTekst[ i = 2 ]
Na pewno tu miało być przypisanie? Poza tym, potencjalnie przekraczasz zakres tablicy dla ostatniego i przedostatniego sprawdzanego elementu tablicy. Oprócz tego, jeśli zamiana się udała, to nie musisz przesuwać
i
 o jeden, tylko możesz przejść od razu na koniec zamienionego tekstu.
P-174190
Brys
Temat założony przez niniejszego użytkownika
» 2019-03-14 21:28:56
Kurde, nie zauważyłem tego. Tam miał być plus.
Poprawiłem trochę i program zdaje się działać.
C/C++
{
    int j = 0;
    int ileZnakow = sTekst.size();
    for( int i = 0; i <( ileZnakow - 2 ); i++ )
    {
        if(( sTekst[ i ] == '<' ) &&( sTekst[ i + 1 ] == 'b' ) &&( sTekst[ i + 2 ] == '>' ) )
        {
            sTekst.replace( i, 3, "[b]" );
           
        }
    }
   
   
    j = 0;
    ileZnakow = sTekst.size();
    for( int i = 0; i <( ileZnakow - 3 ); i++ )
    {
        if(( sTekst[ i ] == '<' ) &&( sTekst[ i + 1 ] == '/' ) &&( sTekst[ i + 2 ] == 'b' ) &&( sTekst[ i + 3 ] == '>' ) )
        {
            sTekst.replace( i, 4, "[/b]" );
           
        }
    }
   
   
    j = 0;
    ileZnakow = sTekst.size();
    for( int i = 0; i < ileZnakow; i++ )
    {
        if(( sTekst[ i ] != ' ' ) ||( sTekst[ i + 1 ] != ' ' ) )
        {
            sTekst[ j ] = sTekst[ i ];
            j++;
        }
    }
    sTekst.resize( j );
   
    return sTekst;
   
}
P-174191
jankowalski25
» 2019-03-14 23:03:53
Jak chcesz mieć mniej pętli, to idź znak po znaku.
Nadal masz trzy pętle. Jeśli chcesz mieć ich mniej, to możesz złożyć to wszystko w jedną pętlę. Oczywiście sensowność czegoś takiego jest dyskusyjna (bo na przykład dodawanie kolejnych znaczników będzie bardziej uciążliwe), niemniej jednak zawsze wystarczy tutaj pojedyncza pętla przechodząca liniowo po tekście, ile by w niej warunków nie było.

int j = 0;
To można dać przy samych spacjach, skoro nigdzie indziej z tego nie korzystasz.

ileZnakow = sTekst.size();
Sama podmiana nawiasów ostrych na kwadratowe nie zmienia tutaj długości tekstu, więc nie trzeba jej ciągle pobierać.

if(( sTekst[ i ] == '<' ) &&( sTekst[ i + 1 ] == '/' ) &&( sTekst[ i + 2 ] == 'b' ) &&( sTekst[ i + 3 ] == '>' ) )
Podejście „znak po znaku” sprawdza się wtedy, kiedy chcesz na przykład koniecznie zrobić wszystko za jednym zamachem w jednej pętli. Jeśli jednak używasz oddzielnych pętli do każdego znacznika, to tutaj wystarczy zwykłe find(), będzie prościej, czytelniej i łatwiej to rozbudowywać o nowe znaczniki.
P-174193
« 1 » 2
  Strona 1 z 2 Następna strona