# Wörter aus String mit mehreren Wörtern extrahieren?



## gutsch (27. März 2013)

Hey! Ich habe hier ein kleines Problem. Wenn es denn ein solches ist. Google war bisher wenig hilfreich und auch hier in der Suche bin ich nicht so recht fündig geworden.

Also folgendes: Bei dem Programm wird aus der Konsole über getline(cin, input) halt ein Text eingelesen. input stellt einen string dar (Vielleicht ist schon das ein Problem?). Nun würde ich gerne die einzelnen Worte extrahieren und zumindest temporär in einen anderen String packen. Sprich alles was bis zum Leerzeichen kommt. Dann wird das verarbeitet und wieder bis zum Leerzeichen usw.

Ist das möglich? Also auch mit Strings? Wäre super, wenn mir da jemand einen Hinweis geben könnte 

Das hier ist übrigens das Schnipsel:


```
void einlesen(string &input) {
	cout << "Text eingeben: " << endl;
	getline(cin, input);
	cout << "Ihre Eingabe war: " << input << endl;
}
```
Beste!


----------



## deepthroat (27. März 2013)

Hi.

Verwende einfach einen std::istringstream dem du die gelesene Zeile bei der Initialisierung übergibst. Danach kannst du die Worte mit dem >> Operator in einer while Schleife auslesen.

Du solltest außerdem immer prüfen ob die Ein-/Ausgabeoperationen erfolgreich waren.

Bsp:
	
	
	



```
bool einlesen(string &input) {
    cout << "Text eingeben: " << endl;
    if (getline(cin, input)) {
      cout << "Ihre Eingabe war: " << input << endl;
      return true;
    } else {
      return false;
    }
}
```


----------



## gutsch (27. März 2013)

Hm. std::istringstream ist mir quasi unbekannt ... Versuche das gerade zu googlen und zu verstehen. Bisher nur c gemacht. Ist eines der ersten c++ die gemacht werden sollen.
Den Rest kann ich mir ganz gut vorstellen. Auch dank dem Beispiel 

Habe ich das richtig verstanden?
istringstream kann als Ein- und Ausgabemedium vom Datenstrom verwendet werden?


```
bool einlesen(string &input) {
	

    cout << "Text eingeben: " << endl;
    if (getline(cin, input)) {
        istringstream tin(input);
		cout << "Ihre Eingabe war: " << tin << endl;
		return true; } 
	else { 
		return false; }
}
```

Ist das so im Grunde richtig? Bis auf die Ausgabe. Da steht, wenn ich das richtig verstanden habe, nun einfache die Adr.? Das war einfach nur zum schauen, was passiert 
Sollte das Stimmen könnte ich dann nun einfach eine weitere Funktion aufrufen, und tin z.b. übergeben, um das ganze zu verarbeiten? 
Was c++ angeht, ist das einzige was ich bisher hatte cin und cout


----------



## deepthroat (27. März 2013)

gutsch hat gesagt.:


> Habe ich das richtig verstanden?
> istringstream kann als Ein- und Ausgabemedium vom Datenstrom verwendet werden?


Ein *i*stringstream ist ein Eingabestrom, kann also anstelle jedes anderen std::istream verwendet werden. (cin ist auch nur ein Eingabestrom)

Das Medium dieses Stroms ist ein String, im Gegensatz zum std::ifstream dessen Medium ein *f*ile ist.


gutsch hat gesagt.:


> ```
> bool einlesen(string &input) {
> 
> 
> ...


Ja.


gutsch hat gesagt.:


> Sollte das Stimmen könnte ich dann nun einfach eine weitere Funktion aufrufen, und tin z.b. übergeben, um das ganze zu verarbeiten?


Ja, natürlich. Allerdings nur als Referenz, die std:: Eingabeströme sind nicht kopierbar.


----------



## gutsch (27. März 2013)

deepthroat hat gesagt.:


> Ein *i*stringstream ist ein Eingabestrom, kann also anstelle jedes anderen std::istream verwendet werden. (cin ist auch nur ein Eingabestrom)



ah ok. Dann *o*stringstream für *o*ut vermute ich 

Dann will ich mich mal weiter versuchen. Danke

Also. Einlesen, verarbeiten und ausgeben läuft soweit.
2 Kleinigkeiten(?) stören mich aber noch:
1. Großbuchstaben können eingegeben werden, sollen aber als kleinbuchstaben wieder ausgegeben werden. In c habe ich einfach abgefragt ob der char z.B. 97 ist und dann 32 addiert. Danach war es halt ein kleiner. Nun habe ich schon ein wenig gegoogled, aber relativ erfolglos. Gibt es in c++ etwas, was den ganzen string "verkleinert? Habe was von tolower (glaube ich c? wir durften es nie nutzen) und transform gelesen. Die sind aber in Bibliotheken drin, die ich glaube ich nicht nutzen darf.
2. Es kann passieren, dass in einem der Wörter mittendrin ein Satzzeichen ist. Das sollte nach Möglichkeit ans Ende des Wortes geschoben werden. Hab es mit .find und push_back versucht, aber ziemlich erfolglos. :/

Das wäre es eigentlich. Der Rest läuft soweit. Wäre super, wenn du mir da auch noch n Schubs in die richtige Richtung geben könntest


----------



## deepthroat (27. März 2013)

gutsch hat gesagt.:


> Also. Einlesen, verarbeiten und ausgeben läuft soweit.
> 2 Kleinigkeiten(?) stören mich aber noch:
> 1. Großbuchstaben können eingegeben werden, sollen aber als kleinbuchstaben wieder ausgegeben werden. In c habe ich einfach abgefragt ob der char z.B. 97 ist und dann 32 addiert. Danach war es halt ein kleiner. Nun habe ich schon ein wenig gegoogled, aber relativ erfolglos. Gibt es in c++ etwas, was den ganzen string "verkleinert? Habe was von tolower (glaube ich c? wir durften es nie nutzen) und transform gelesen. Die sind aber in Bibliotheken drin, die ich glaube ich nicht nutzen darf.


Ja, tolower mit transform wäre eine elegante Möglichkeit.

Wenn du das nicht verwenden darfst, dann mußt du halt per Hand über die Zeichen des std::string iterieren und die Zeichen entsprechend manuell ersetzen.


gutsch hat gesagt.:


> 2. Es kann passieren, dass in einem der Wörter mittendrin ein Satzzeichen ist. Das sollte nach Möglichkeit ans Ende des Wortes geschoben werden. Hab es mit .find und push_back versucht, aber ziemlich erfolglos. :/


Da fehlt noch ein Schritt.

1. find
2. erase
3. push_back


----------



## gutsch (28. März 2013)

Besten Dank! Ich denke, dann soll ich das morgen früh wohl hinbekommen 

edit:

```
for(int i = 0; i < input.size() ; i++) {
			if ( ((input[i] >= 65) && (input[i] <= 90)) || (input[i] == 220) || (input[i] == 196) || (input[i] == 214) ) /* Großbuchstabe? */ 
				input[i] = input[i] + 32;
		}
```

So habe ich das nun mit den Großbuchstaben geregelt. Funktioniert. Und ist ja auch nicht besonders lang. Allerdings habe ich mir das auch nur aus einem meiner c programme "geklaut" und i<input.size() eingefügt. Dürfte so auch richtig sein, oder?

Das mit dem find, erase und push_back funktioniert bei mir noch nicht so ganz. Was liefert denn str.find oder str. find_first_of als Rückgabewert, wenn nichts gefunden wurde? Denn wenn nichts drin ist, braucht ja nichts erased oder gepushed werden.


```
int index = 0;
	string alt, neu;	
	
	/* Find, Erase, Push_back */
	/*index = alt.find_first_of(".,:;-");*/
	/*neu= alt.erase(index, 0); */
	/*neu.push_back(index);*/

	temp = neu;
```

Ich denke, dass dort noch eine if reingehört, ob er was gefunden hat. Das soll auch nicht das große Problem sein. Eher habe ich ein Problem damit, dass - wenn ein . im Wort war - er ein "Herzchen" ans Ende pushed oO

// edit:
oder muss das vielleicht neu.push_back(neu[index]) oder so sein?

Ob das so:


```
/* Find, Erase, Push_back */
	index = neu.find_first_of(".,:;-");	
	
	neu = neu.erase(index, 1); 
	neu.push_back(alt[index]);

	temp = neu;
```

wohl hinkommt? Dann würde nur noch eine Abfrage fehlen. So macht es was es soll


```
/* Find, Erase, Push_back */
	index = neu.find_first_of(".,:;-");	
	if(index != 0xffffffff) {
		neu = neu.erase(index, 1); 
		neu.push_back(alt[index]);
	} 

	temp = neu + " ";
```

Ist das wirklich der Rückgabewert bei index, wenn nichts gefunden wird?
Und gibt es eine andere Möglichkeit beim zusammenfügen der Wörter ein Leerzeichen einzufügen? 


```
output += temp;
```
 Das ist der Teil wo die zusammengefügt werden. Und dann auch direkt ausgegeben. output ist n einfacher string.


----------



## deepthroat (28. März 2013)

gutsch hat gesagt.:


> ```
> for(int i = 0; i < input.size() ; i++) {
> if ( ((input[i] >= 65) && (input[i] <= 90)) || (input[i] == 220) || (input[i] == 196) || (input[i] == 214) ) /* Großbuchstabe? */
> input[i] = input[i] + 32;
> ...


Ja, passt.


gutsch hat gesagt.:


> Das mit dem find, erase und push_back funktioniert bei mir noch nicht so ganz. Was liefert denn str.find oder str. find_first_of als Rückgabewert, wenn nichts gefunden wurde? Denn wenn nichts drin ist, braucht ja nichts erased oder gepushed werden.


Die find Methoden geben einen speziellen Wert zurück wenn nichts gefunden wird:

std::string::npos

(In welche Referenz hast du denn geschaut, das muss doch aber drin stehen.. ?

 Tip: http://www.cplusplus.com/reference/string/basic_string/find/)


gutsch hat gesagt.:


> Ob das so:
> 
> 
> ```
> ...


Ja, obwohl du natürlich nicht den ganzen String kopieren mußt wenn du nur ein Zeichen ändern willst. Speicher dir einfach nur das eine Zeichen welches du löschen möchtest.

Und erase modifiziert den String, es ist nicht notwendig das Resultat wieder an den String zuzuweisen. Vielmehr gibt die erase Methode eine Referenz auf den gleichen String zurück, so dass man mehrere Aufrufe direkt verknüpfen kann.


```
/* Find, Erase, Push_back */
	index = alt.find_first_of(".,:;-");	
	if(index != std::string::npos) {
                char c = alt[index];
		alt.erase(index, 1).push_back(c);
	} 

	temp = alt + " ";
```



gutsch hat gesagt.:


> Und gibt es eine andere Möglichkeit beim zusammenfügen der Wörter ein Leerzeichen einzufügen?
> 
> 
> ```
> ...


Du könntest zum zusammenfügen einen ostringstream verwenden. Oder statt des += Operators die append Methode...

Allerdings wenn du es danach direkt ausgeben willst, dann kannst du dir das zusammenbasteln im Speicher auch sparen und es gleich ausgeben.


----------



## gutsch (28. März 2013)

Alles klar. Danke! 

Besonders bei dem letzten Satz komme ich mir nun ein wenig doof vor  Da hätte ich auch dran denken können ...


----------

