2016-07-13 6 views
0

Probleme mit dem Verständnis von Teilen des Codes; die Ausgabe, die ich bekomme, ist auch falsch. Das Problem besteht darin, alle Leerzeichen in einer Zeichenfolge durch '% 20' zu ersetzen. Der vollständige Code ist unten abgebildet. Es kompiliert, läuft aber nicht genau so, wie es sollte.Ersetzen aller Leerzeichen in einer Zeichenfolge durch '% 20' (C++)

#include <iostream> 
#include <string> 
using namespace std; 

void replaceSpaces(string str){ 

    //Getting the length of the string, counting the number of spaces 
    int strLen = str.length(); 
    int i, count = 0; 
    for (i = 0; i <= strLen; i++) { 
     if(str[i]==' ') 
     count++; 
    } 

    //Determining the new length needed to allocate for replacement characters '%20' 
    int newLength = strLen + count * 2; 

    str[newLength] = '\0'; 
    for (i = strLen - 1; i >= 0; i--) { 
     if (str[i] == ' ') { 
      str[newLength - 1] = '0'; 
      str[newLength - 2] = '2'; 
      str[newLength - 3] = '%'; 
      newLength = newLength - 3; 
     } 

     else { 
      str[newLength - 1] = str[i]; 
      newLength = newLength -1; 
     } 
    } 
    cout << str <<endl; 

} 

int main() { 

    string str = "hello jellybean hello"; 
    replaceSpaces(str); 

    return 0; 

} 

ich wahrscheinlich ich etwas fehlt offensichtlich, aber wenn für den neuen String-Länge in dieser Zeile Zuweisung:

int newLength = strLen + count * 2;

Hier haben wir die Anzahl der Räume, die durch 2 multipliziert werden, aber Wenn wir versuchen, alle Räume durch '% 20' zu ersetzen, warum nicht mit 3 multiplizieren?


str[newLength] = '\0';

Enthält diese Linie zeigt, dass die Position hinter dem letzten Zeichen in der Zeichenfolge einen Nullraum zugeordnet ist?


Bin auch verwirrt über die else Aussage.

else { 
     str[newLength - 1] = str[i]; 
     newLength = newLength -1; 
    } 

Nicht sicher, ob ich den Umstand vollständig verstehe, wenn dies ausgeführt würde.


Wenn die Funktionen kompiliert und ausgeführt werden, wenn

string str = "hello jellybean hello";

die erwartete Ausgabe hallo% 20jellybean% 20hello, außer die Ausgabe erhalte ich sein würde, ist hallo% 20jellybean% 20h.

In Bezug auf Zeit Komplexität, da gibt es zwei unabhängige for Schleifen, wäre die Zeit Komplexität O (n)?

Ich weiß, ich stelle viele verschiedene Fragen, vielen Dank im Voraus für Antworten!

+1

Wenn Sie eine beliebige Stelle in einer Zeichenfolge indizieren (und festlegen), wird die Zeichenfolge nicht automatisch auf diese Länge vergrößert. Danach habe ich aufgehört zu suchen. Naja, ich habe die Frage über '* 3 'gelesen. Für jede Ersetzung subtrahieren Sie ein Zeichen - den Originalraum - und addieren 3. So ... – davidbak

+0

'str [newLength]' greift auf den Speicherplatz zu, der über den Speicherplatz hinausgeht, der für 'str' reserviert ist. Was Sie tun möchten, ist eine neue Zeichenfolge mit der neuen Größe zu erstellen, kopieren Sie die alte Zeichenfolge über und ersetzen Sie die Leerzeichen mit "% 20" – ShuberFu

+0

Der einfachste Ansatz wäre 'strtok()' zu verwenden, um Ihre Zeichenfolge zu spalten an Leerzeichen und Zeichenketten-Token erstellen). Dann iteriere einfach durch die Token und lege ein% 20 zwischen jedes Token ... 'char * tokens = strtok (mein_string," "); while (Token) {cout << Token << "% 20"; Token = strtok (NULL, ""); } ' – Ingenioushax

Antwort

2

Das ist falsch:

str[newLength] = '\0'; 

std::string Objekte ihre NUL Terminator intern pflegen basierend auf ihrer Größe. Sie wollen

str.resize(newLength); 

stattdessen.

+0

Ich habe die Zeile 'str.resize (newLength);' vor dieser Zeile 'str [newLength] = '\ 0';' hinzugefügt. Nach meinem Verständnis wird 'str.resize' die neue String-Länge zuweisen, aber wenn ich versuche, es auszuführen, ist die Ausgabe sehr durcheinander. Könnten Sie etwas mehr Einblick geben? – jellyxbean

+0

@jellyxbean, wie Chris schon erwähnt hat, 'str [newLenght]' ist falsch. Ich hatte das auch in meiner Antwort erwähnt, die du nicht akzeptierst, was natürlich OK ist, aber ich fühle, dass du zu dieser Antwort einfach aufgesprungen bist, ohne es auch zu verstehen. – gsamaras

+0

@gsamaras Ich habe es tatsächlich mit der Funktion str.resize() herausgefunden, weshalb ich diese Antwort stattdessen akzeptierte! Es macht jetzt Sinn; Ich reserviere Speicherplatz für die Zeichenfolge mit einer Größe neuer Länge und setze dann den letzten Index auf '\ 0'. – jellyxbean

1
int newLength = strLen + count * 2; 

sagt Raum (später), die gleich der Länge der Zeichenfolge zuzuweisen, plus die Anzahl von Leerzeichen mit zwei multipliziert gefunden, was Sinn macht.

Zum Beispiel: so glad to help, sollten die Schlitze verwenden, die Leerzeichen in leben für die % und sie werden zwei weitere Steckplätze müssen jeweils für den 20 Teil des Ersatz, die ins Spiel kommen.


Dies ist FALSCH:

str[newLength] = '\0'; 

können Sie nicht sehen? Sie greifen auf Speicher außerhalb der Grenzen Ihrer Zeichenfolge zu. Sie verhalten sich so, als hätten Sie tatsächlich Speicherplatz zugewiesen, der dem newLength entspricht, aber Sie haben das nirgendwo im Code noch nicht.

Eingeschränkter Zugriff auf Ergebnis in Undefined Behavior und das ist schlecht.


Die else-Anweisung ist nur für das Kopieren von nicht-Leerzeichen, aber Sie sollten bereits an diesem Code aufgegeben (wenn es nicht deins) und von vorne anfangen oder/und einen ersten Blick nehmen an: Encode/Decode URLs in C++.

Was das falsche Ergebnis angeht, sollten Sie wissen, dass Sie diesen Punkt der Antwort erreichen, dass dies erwartet wird.

+1

Das hat plötzlich geklickt, ich fühle mich ziemlich albern, weil ich es vorher nicht verstanden habe , Danke! – jellyxbean

+0

Sei nicht @jellyxbean, jeder hat so etwas schon mal erlebt! Froh, dass ich geholfen habe! :) – gsamaras

+0

@jellyxbean, gibt es einen Grund dafür, meine Antwort nicht zu akzeptieren? :) – gsamaras

0

Der Versuch, die Änderung an Ort und Stelle vorzunehmen, ist schwierig. Es ist viel einfacher, eine neue Zeichenfolge zu erstellen:

std::string new_string; 
for (int i = 0; i < str.length(); ++i) { 
    if (str[i] == ' ') 
     new_string += "%20"; 
    else 
     new_string += str[i]; 
} 
return new_string; 

oder, wenn Sie so wollen Bereichs für:

std::string new_string; 
for (char ch : str) { 
    if (ch == ' ') 
     new_string += "%20"; 
    else 
     new_string += ch; 
} 
return new_string; 
0

Sie können dieses String-Argument in Funktion zu referenzieren, dann wird keine Notwendigkeit für neue Zeichenfolge, in anderen Teil des Codes, können Sie die Funktion einfügen, um '2' und '0', und nur Sie müssen den Raum in '&' konvertieren.

void replaceSpaces(string &str) { 
     size_t strLen = str.length(); 
     for (int i = 0; i < strLen; i++) { 
      if (str[i] == ' ') { 
       str[i] = '%'; 
       str.insert(str.begin() + i + 1, '2'); 
       str.insert(str.begin() + i + 2, '0'); 
       strLen += 2; 
      } 
     } 
    } 
+0

Das Modifizieren ist sehr ineffizient. Jeder Aufruf von 'insert()' muss alle verbleibenden Zeichen in der Zeichenfolge kopieren, also ist dies "O (m * n)", wobei "m" die Anzahl der Leerzeichen und "n" die Größe der Zeichenfolge ist. – Barmar

0

Dies ist einfach; ersetzen examplestring mit der Zeichenfolge im Code, und verwenden Sie, wie Sie es:

#include <iostream> //debug output 
#include <string> 

using std::string; 
using std::cout; 
using std::endl; 

//the string to convert 
string examplestring = "this is the example string for spaces into %20"; 

int main() 
{ 
    int countspaces = 0; //its faster to fill a known size 
    for (auto &x : examplestring)if (x == ' ')countspaces++; //counts spaces 

    string newstring; //declare new string 
    newstring.resize(examplestring.size() + (countspaces*3)); //pre-set size to make it run faster 

    int newstringiterator = 0; //keep track of new string location 

    //if ' '(space), place %20 in newstring and add 3 to iteration 
    //else just place the letter and iterate 

    for (int i=0;i<examplestring.size();i++) 
    { 
     if (examplestring[i] == ' ') 
     { 
      newstring.insert(newstringiterator, "%20"); 
      newstringiterator += 3; 
     } 
     else newstring[newstringiterator++] = examplestring[i]; 
    } 

    //final newstring is the original with %20 instead of spaces. 
    cout << newstring << endl; 

    system("PAUSE"); //to read console output 
    return 0; //return to zero 
} 

Dies wird Ausgang newstring, die mit ‚% 20‘ anstelle von Leerzeichen die alte Zeichenfolge ist.