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 #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? |
|
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.. 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 );
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. |
|
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 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; } |
|
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). |
|
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 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ś 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 |
|
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. 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. |
|
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ć. { 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; } |
|
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. 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. |
|
« 1 » 2 |