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

Zadanie 28 - Przemieszczające się podmieniane znaki.

Ostatnio zmodyfikowano 2017-07-14 15:53
Autor Wiadomość
Kaza
Temat założony przez niniejszego użytkownika
Zadanie 28 - Przemieszczające się podmieniane znaki.
» 2017-07-13 20:01:59
Witam wszystkich.
Odpalając świeżo napisany program zauważyłem dziwną właściwość "nowych" tekstów. Ale od początku.

C/C++
#include <iostream>
#include <string>

size_t pozycjaznaku( std::string wjakimtekscie, std::string znak )
{
    size_t pozycja = wjakimtekscie.find( znak );
    if( pozycja == std::string::npos )
    {
        return false;
    }
   
    return pozycja;
}


void zamienznak( std::string & tekst, std::string znak, std::string naco, int ileznakowusunac )
{
   
    do
    {
        tekst.erase( pozycjaznaku( tekst, znak ), ileznakowusunac );
        tekst.insert( pozycjaznaku( tekst, znak ), naco );
    } while( pozycjaznaku( tekst, znak ) != false );
   
}



int main()
{
    std::string tekst = "<b> to jest </b> testowy       napis     <b>:)";
    std::cout << "Tekst przed zmiana:\n";
    std::cout << tekst;
    std::string znak1 = "  ";
    std::string znak2 = " ";
    std::string znak3 = "<";
    std::string znak4 = "[";
    std::string znak5 = ">";
    std::string znak6 = "]";
    zamienznak( tekst, znak1, znak2, 2 );
    zamienznak( tekst, znak3, znak4, 1 );
    zamienznak( tekst, znak5, znak6, 1 );
   
    std::cout << "\n\nTekst po zmianie:\n";
    std::cout << tekst;
   
   
   
    return 0;
}


Program zmienia niemal każdy znak tak jak tego oczekiwałem, jednak pierwszy zmieniony znak z każdego rodzaju pojawia się na początku tekstu. Myślałem, że może pokręciłem coś z wartościami pozycji, jednak problem występuje niezależnie od tego jak długi jest tekst, na jakich pozycjach występują znaki do zmiany, oraz jakiego rodzaju są to znaki.

Czytałem cały kod mnóstwo razy, analizując każdą linijkę z osobna, ale nie mam pojęcia co może powodować przeskakiwanie znaków na początek tekstu.

Czy ktoś bardziej rozgarnięty mógłby wyjaśnić mi powód tej "literowej migracji"?
P-163249
carlosmay
» 2017-07-13 22:16:12
W funkcji
pozycjaznaku
 kosmetyka:
Zamiast zwracać wartość logiczną
false
, gdy funkcja ma zadeklarowany zwracany typ na
std::size_t
(jest bardzo nieintuicyjnie i może wprowadzać w błąd), zwracaj wartość jaką zwraca metoda
find
, gdy nic nie znajdzie.
C/C++
size_t pozycjaznaku( std::string wjakimtekscie, std::string znak )
{
    size_t pozycja = wjakimtekscie.find( znak );
    if( pozycja == std::string::npos )
    {
        return std::string::npos;
    }
   
    return pozycja;
}
W zasadzie ta funkcja mogłaby zniknąć z kodu :).
Bo robi dokładnie
return wjakimtekscie.find( znak );



W funkcji
zamienznak
 jest błąd logiczny:
C/C++
do
{
    tekst.erase( pozycjaznaku( tekst, znak ), ileznakowusunac ); // usuwasz znak ze znalezionej pozycji
    // i już nie ma tego znaku, a w następnej linijce znów szukasz pozycji (już nieistniejącego) znaku
    tekst.insert( pozycjaznaku( tekst, znak ), naco ); // wstawiasz na znalezionej pozycji, ale innej niż oczekujesz
} while( pozycjaznaku( tekst, znak ) != false );

Zapamiętuj zwracaną pozycję z funkcji
pozycjaznaku
 i na tej wartości operuj.
std::size_t pos = pozycjaznaku( tekst, znak );
i w metodach
erase
 oraz
insert
 używaj właśnie zmiennej
pos
.

Kod jest zamotany i musiałem użyć debuggera (jak najszybciej poznaj) aby rozkminić, co się dzieje w kodzie.
P-163253
Kaza
Temat założony przez niniejszego użytkownika
Działa tak jak powinno.
» 2017-07-14 14:56:28
C/C++
#include <iostream>
#include <string>


void zamienznak( std::string & tekst, std::string znak, std::string naco, int ileznakowusunac )
{
    std::size_t pozycja;
   
    do
    { pozycja = tekst.find( znak );
        if( pozycja == std::string::npos )
             return;
        else
        { tekst.erase( pozycja, ileznakowusunac );
            tekst.insert( pozycja, naco ); }
       
    }
    while( pozycja != std::string::npos );
   
}



int main()
{
    std::string tekst = "<b> to jest </b> testowy       napis     <b>:)";
    std::cout << "Tekst przed zmiana:\n";
    std::cout << tekst;
    std::string znak1 = "  ";
    std::string znak2 = " ";
    std::string znak3 = "<";
    std::string znak4 = "[";
    std::string znak5 = ">";
    std::string znak6 = "]";
    zamienznak( tekst, znak1, znak2, 2 );
    zamienznak( tekst, znak3, znak4, 1 );
    zamienznak( tekst, znak5, znak6, 1 );
   
    std::cout << "\n\nTekst po zmianie:\n";
    std::cout << tekst;
   
   
   
    return 0;
}

Jak kolega poradził, zrezygnowałem z funkcji
size_t pozycjaznaku( std::string wjakimtekscie, std::string znak )
.
Wielkie dzięki za pomoc. Praca z debuggerem nie pojawiła się jeszcze w kursie, dlatego nawet nie wiedziałbym jak z niego korzystać:P
Została jeszcze jedna rzecz, która mnie intryguje w tym kodzie. Otóż w obecnej formie, kiedy w kodzie występują linijki
C/C++
if( pozycja == std::string::npos )
     return;
wszystko działa jak należy. Jednak kiedy ich zabraknie program zamyka się po błędzie. Czy funkcja
while( pozycja != std::string::npos );
 nie powinna być samowystarczalna w tej postaci, to jest kończyć funkcję
do
, kiedy nowe znaki nie zostaną znalezione?
P-163280
carlosmay
» 2017-07-14 15:53:40
Praca z debuggerem nie pojawiła się jeszcze w kursie, dlatego nawet nie wiedziałbym jak z niego korzystać:P
... i się nie pojawi :P. Jest (chyba) tylko wzmianka, że coś takiego istnieje.
Pytasz googla jak korzystać z debuggera w IDE, z którego korzystasz lub zaglądasz do dokumentacji tego IDE.
Ewentualnie dla programów kompilowanych z cmd szukasz informacji w dokumentacji kompilatora.

Czy funkcja
while( pozycja != std::string::npos );
 nie powinna być samowystarczalna w tej postaci
Nie. Zastanów się, jaką wartość ma zmienna pozycja i gdzie nadajesz jej wartość.

Po wyrzuceniu:
C/C++
if( pozycja == std::string::npos )
     return;

zastaje
C/C++
do
{
    pozycja = tekst.find( znak ); // pozycja = std::string::npos gdy nie znaleziono znaku
    tekst.erase( pozycja, ileznakowusunac ); // tutaj: tekst.erase(std::string::npos, ileznakowusunac);
    tekst.insert( pozycja, naco ); // tutaj: tekst.insert(tekst.insert(std::string::npos, naco);       
}
while( pozycja != std::string::npos ); // przerwanie pętli jest dopiero tutaj

P-163284
« 1 »
  Strona 1 z 1