Iteratory stringów - zamiana sekwencji

Iteratory stringów - zamiana sekwencji
adgjmptw's world
  • Rejestracja:prawie 5 lat
  • Ostatnio:prawie 5 lat
  • Postów:4
0

Cześć.
Dostałem zadanie, w którym trzeba zamienić sekwencję \r\n na** \n** i odwrotnie. Mogę korzystać jedynie z #include <string>.
Nie wiem gdzie leży błąd, kombinowałem na wszelkie sposoby i niestety nic nie udało mi się wymyśleć.
Czy ostatni else if jest dobrze zapisany? Czy może on wymaga rozbicia r i **n **za pomocą &&.
Czy nie powinienem zapisywać *target++ na dwie linijki? np. ' \\ ' i ' r '
Z góry dziękuje za każdą wskazówkę :)

string do zadania : "peppermint 1001\rbubbles\nballoon\r\ngum"
prawidłowa odpowiedź:** "peppermint 1001\rbubbles\r\nballoon\ngum"**

Kopiuj
std::string::iterator function(std::string::const_iterator begin, std::string::const_iterator end, std::string::iterator target) {

	while (begin < end) { 
		if (*begin == '\r') {
			*target++ = '\r';
			begin++;
		}
		else if (*begin == '\n') {
			*target++ = '\r';
			*target++ = '\n';
			begin++;
		}
		else if (*begin == '\r\n') {
			*target++ = '\n';
			begin ++;
		}
		else {
			*target++ = *begin++;
		}
	}
	return target;
}
adgjmptw's world
Funkcja musi przyjmować niemodyfikujący iterator początkowy i końcowy łańcuch wycinka tekstowego oraz modyfikujący iterator początkowy innego wycinka.
TomaszLiMoon
  • Rejestracja:prawie 10 lat
  • Ostatnio:około 2 godziny
  • Postów:530
0
Kopiuj
#include <iostream>

using namespace std;

string raw( char c )
{
    switch( c )
    {
        case '\n': return "\\n";
        case '\r': return "\\r";
        default  : return string{c};
    }
}

string change( const string& target )
{
    string result {};

    for( auto iter {target.cbegin()} ; iter!=target.cend() ; ++iter )
    {
        if( *iter == '\n' )
        {
            if( iter != target.cbegin() && *(iter-1) == '\r' )
            {
                result += raw('\n');
            }
            else
            {
                result += raw('\r')+raw('\n');
            }
        }
        else if( ! ( ( (iter+1) != target.cend() ) && ( *iter == '\r' && *(iter+1) == '\n' ) ) ) result += raw(*iter);
    }

    return result;
}

int main()
{
   cout << R"(peppermint 1001\rbubbles\nballoon\r\ngum)" << " - > " << change("peppermint 1001\rbubbles\nballoon\r\ngum") << "\n";
   return 0;
}

adgjmptw's world
Dziękuję i przepraszam nie sprecyzowałem. Funkcja musi przyjmować niemodyfikujący iterator początkowy i końcowy łańcuch wycinka tekstowego oraz modyfikujący iterator początkowy innego wycinka. Czyli coś takiego jak jest u mnie w kodzie.
TomaszLiMoon
Aby dostosować funkcję change do warunków zadania, wystarczy zmodyfikować jej sygnaturę oraz zamienić zmienną result na iterator do docelowego stringa.
enedil
  • Rejestracja:prawie 12 lat
  • Ostatnio:4 minuty
  • Postów:1027
1

Problem polega na tym, że \r\n to nie jeden znak, a dwa.

MarekR22
Moderator C/C++
  • Rejestracja:około 17 lat
  • Ostatnio:4 minuty
0
Kopiuj
template<typename In, typename Out>
Out convert_win_to_unix_line_endings(In b, In e, Out r)
{
     while (b != e) {
          while (b != e && *b != '\r')
               *r++ = *b++;
          if (b == e) break;
          ++b;
          if (b == e || *b != '\n') {
              *r++ = '\r';
          }
     }
     return r;
}

Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
edytowany 3x, ostatnio: MarekR22
TomaszLiMoon
Swoją drogą, zawsze obawiam się takich przypadków, w których użytkownik zapomni "ustawić" odpowiednią wielkość stringowi z którym związany jest iterator r.
MarekR22
jestem tego świadomy, co widać po nazwie funkcji.
adgjmptw's world
  • Rejestracja:prawie 5 lat
  • Ostatnio:prawie 5 lat
  • Postów:4
0

Moim zdaniem powinno to hulać, ale program ma nadal obiekcje co do tego. Jakieś wskazówki?

Kopiuj
std::string::iterator function(std::string::const_iterator begin, std::string::const_iterator end, std::string::iterator target) {

	while ( begin < end ) {
		
		if ( *begin == '\r') {
			if( *(begin +1) == '\n') {
				*target++ = '\n';
				begin++;
	
			}
			else {
				*target++ ='\r';
				begin++;	
			}
		}
		else if (*begin == '\n') {
			*target++ = ('\r' + '\n');
			begin++;
		}
		else {
			*target++ = *begin++;
		}
	}
}
Zobacz pozostałe 2 komentarze
adgjmptw's world
A jakieś pomysły jak to prawidłowo rozbić? Bo przeniesienie \n do nowej linii w tym przypadku nic nie da.
MarekR22
zrób to w dwóch liniach/wyrażeniach.
MarekR22
Jeszcze masz potencjalne UB w *(begin +1).
adgjmptw's world
Zrobienie z tego dwóch wyrażeń nic nie dało. UB - nie rozumiem dlaczego.
MarekR22
bo begin + 1 może być równe end, które zwykle wskazuje poza zakres bufora. U ciebie się to nie trafi, bo dla napisy są zwykle zakończone zerem.
lion137
  • Rejestracja:około 8 lat
  • Ostatnio:2 minuty
  • Postów:4927
0

A jakaś kombinacja string::find i string::replace nie pomoże?


tajny_agent
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad rok
  • Postów:1340
2

A takie cuś nie styknie?

Kopiuj
string::iterator convert(string::const_iterator begin, string::const_iterator end, string::iterator dest)
{
    while (begin != end) {
        if (*begin == '\n') {
            *dest++ = '\r';
        }
        else if (*begin == '\r' && (begin+1) != end && *(begin+1) == '\n') {
            ++begin;
        }
        *dest++ = *begin++;
    }
    return dest;
}

"I love C++. It's the best language in the world right now for me to write the code that i need and want to write"
~ Herb Sutter
adgjmptw's world
Wow, dziękuje bardzo za pomoc.
MarekR22
Moderator C/C++
  • Rejestracja:około 17 lat
  • Ostatnio:4 minuty
1

Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
edytowany 2x, ostatnio: MarekR22

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.