• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Usuwanie spacji obok siebie

0 głosów
81 wizyt
pytanie zadane 7 grudnia 2018 w C i C++ przez Michał_Warmuz Gaduła (4,390 p.)

Czesc pisze zadanie z C++ 0x

i musze podmienic oraz usunac spacje ktore wystepuja obok siebie. Podmienianie działa ale nie usuwanie spacji znaczy usuwa ale tylko czesc tych spacji 

#include <iostream>
#include <string>

using namespace std;

string konwertuj( string & sTekst )
{
    string sWynik;

    for(int i=0; i<=sTekst.size(); i++) {

        if(sTekst[i] == '<') {

            sTekst.erase(i, 1);
            sTekst.insert(i, "[");
        }
        if(sTekst[i] == '>') {

            sTekst.erase(i, 1);
            sTekst.insert(i, "]");
        }
        if(sTekst[i] == ' ' && sTekst[i+1] == ' ') {
            sTekst.erase(i, 1);
        }
    }
    sWynik = sTekst;
    return sWynik;
}
int main()
{
    string tekst = "<b>to jest </b> testowy       napis     <b>:)";
    cout << tekst<<endl;
    cout << konwertuj( tekst)<<endl;

    return 0;
}

 

2 odpowiedzi

+2 głosów
odpowiedź 7 grudnia 2018 przez RafalS VIP (105,130 p.)
wybrane 7 grudnia 2018 przez Michał_Warmuz
 
Najlepsza

Ten kod jest strasznie przekombinowany.

  1. std::string w C++ nie jest immutable, więc zamiast:
    sTekst.erase(i, 1);
    sTekst.insert(i, "[");

    które tak na marginesie sprawia, że cały string(lub tylko czesc z prawej strony) jest przepisywany dwa razy :D zrob po prostu tak:

    sTekst[i]='[';
  2. 	sWynik = sTekst;
    	return sWynik;

    możesz po prostu:

    return sTekst;
  3. Po co ten przedrostek przed nazwą zmiennych. Czyżby od typu? Takie praktyki to przestarzałość. Dzisiaj mamy IDE i wystarczy najechać na nazwe zmiennej zeby sprawdzic jej typ.

  4. for (int i = 0; i <= sTekst.size(); i++) {
    ...
    sTekst[i + 1]

    Wychodzisz poza zakres tablicy. i maksymalnie jest rowne size, wiec odwolujesz sie do sTekst[size+1]. O 2 indeksy za stringiem. Technicznie rzecz biorąc o 1, bo s[s.size()] jest zawsze znakiem null '\n'.

A teraz do rzeczy:

		if (sTekst[i] == ' ' && sTekst[i + 1] == ' ') {
			sTekst.erase(i, 1);
		}

usuwasz jedną spacje. Usuwanie ze stringa w petli nie jest najlepszym pomyslem, bo po pierwsze trzeba modyfikować iterator i ręcznie, co jest nieintuicyjne i tak jak wspomnialem przy kazdym usunieciu elementy po prawej są przepisywane o 1 miejsce w lewo, więc lepiej już wpisywać do nowego stringa elementy, które zostają zamiast usuwać ze starego w miejscu.

Normalnie użyłbym idiomu remove-erase, ktory wydajnie usuwa wiele elementow ze srodka kontenera bez ciaglego przepisywania elementow, ale tutaj chodzi o usuniecie roznych podstringow - zlozonych z roznej ilosci spacji obok siebie. Co od razu narzuca regexy:

regex_replace(tekst, regex{ "\\s{2,}" }, " ");

EDIT: jesli nie znasz regexow i na razie nie chcesz poznwac to mozna to zrobic np tak:

string konwertuj(string & sTekst)
{
	string sWynik;
	bool wasSpace = false;
	for (char c : sTekst) {
		if (c != ' ') {
			wasSpace = false;
			sWynik += c;
		}
		else if (!wasSpace) {
			sWynik += c;
			wasSpace = true;
		}
	}
	return sWynik;
}

lub tak:

string konwertuj(string & sTekst)
{
    string sWynik;
    if (sTekst.size() > 0) {
        sWynik += sTekst[0];
    }
    for (size_t i = 1; i < sTekst.size(); i++)
    {
        if (sTekst[i] != ' ' || sTekst[i - 1] != ' ') {
            sWynik+=sTekst[i];
        }
    }
    return sWynik;
}

 

komentarz 7 grudnia 2018 przez Hipcio Szeryf (86,060 p.)
Do usuwania nadmiaru spacji można użyć std::unique.
+2 głosów
odpowiedź 7 grudnia 2018 przez kamerek Obywatel (1,280 p.)

Cześć,

Fajnie napisany kod.

Brakuje jedynie jednej linii: i--; w warunku, który usuwa wielokrotne spacje.

if(sTekst[i] == ' ' && sTekst[i+1] == ' ') {
            sTekst.erase(i, 1);
            i--;
        }

Po usunięciu znaku z Tekstu trzeba zmniejszyć iterator pętli, żeby kolejny raz poprawnie przeszukać tekst.

pozdrawiam

komentarz 7 grudnia 2018 przez mokrowski Szeryf (99,820 p.)
Masz tu UB. Czytasz indeks poza zakresem string'a.
komentarz 7 grudnia 2018 przez kamerek Obywatel (1,280 p.)

Możesz trochę jaśniej ? Czy masz na myśli przypadek gdy pierwsze dwa znaki to spacje?

Można to rozwiązać:

if(sTekst[i] == ' ' && sTekst[i+1] == ' ') {
            sTekst.erase(i, 1);
            if(i) i--;
        }

 

komentarz 7 grudnia 2018 przez mokrowski Szeryf (99,820 p.)

Co się stanie jeśli indeks i będzie ostatnim znakiem w string'u? Dostęp do i + 1 nastąpi już "za ostatnim znakiem" string'a. Przez to zachowanie będzie niezdefiniowane.

Poza tym to...

for(int i = 0; i <= sTekst.size(); i++)

.. także jest błędne. Nierówność powinna być "ostra".

Podobne pytania

0 głosów
1 odpowiedź 452 wizyt
pytanie zadane 12 czerwca 2018 w Python, Django przez Jayix Użytkownik (630 p.)
0 głosów
1 odpowiedź 178 wizyt
pytanie zadane 4 maja 2018 w C i C++ przez Szymek_sw Początkujący (350 p.)
0 głosów
1 odpowiedź 81 wizyt
pytanie zadane 14 stycznia 2018 w C i C++ przez mn130496 Bywalec (2,990 p.)
Porady nie od parady
Możesz ukryć, zamknąć lub zmodyfikować swoje pytanie, za pomocą przycisków znajdujących się pod nim. Nie krępuj się poprawić pochopnie opublikowanego pytania czy zamknąć go po uzyskaniu satysfakcjonującej odpowiedzi. Umożliwi to zachowanie porządku na forum.Przyciski pytania

61,284 zapytań

107,207 odpowiedzi

223,242 komentarzy

32,692 pasjonatów

Przeglądających: 326
Pasjonatów: 31 Gości: 295

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto dwie polecane książki warte uwagi. Pełną listę znajdziesz tutaj.

...