• Apfeltalk ändert einen Teil seiner Allgemeinen Geschäftsbedingungen (AGB), das Löschen von Useraccounts betreffend.
    Näheres könnt Ihr hier nachlesen: AGB-Änderung
  • Viele hassen ihn, manche schwören auf ihn, wir aber möchten unbedingt sehen, welche Bilder Ihr vor Eurem geistigen Auge bzw. vor der Linse Eures iPhone oder iPad sehen könnt, wenn Ihr dieses Wort hört oder lest. Macht mit und beteiligt Euch an unserem Frühjahrsputz ---> Klick

C++ Strings

blutaermer

Ingrid Marie
Registriert
31.12.03
Beiträge
273
hallo,

ich versuche in C++ aus strings zeichen die ich nicht mag zu ersetzen. das klappt auch ganz gut mit dem gemeinen punkt ('.'). mit dem dollarzeichen ('$') und dem leerzeichen (' ') jedoch nicht. meine dumpfbacken methode sieht so aus:

Code:
std::string Name;
...
size_t found;
std::string str_point = ".";
for (int i=0;i==0;) {
    found = Name.find(str_point);
    if (found == std::string::npos){
	i=1;
    } else {
        Name.replace(Name.find(str_point),str_point.length(),"_");
    }
}

ein punkt wird also durch ein underscore ersetzt. kennt jemand eine todsichere methode um das ganze auch mit '$' und ' ' hinzubekommen?
 

Mitglied 7974

Gast
Ich bin kein C++-Guru, aber das hat bei mir mit gcc-Version 4.1.2 und dem Aufruf "g++ -o test test.cpp" geklappt:

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

void replace(string& in, string pattern, string replacement);

int main() {
   string Name;
   Name = "Ein Te$t mit $";
   replace(Name, "$", "_");
   replace(Name, " ", "_");
   cout << Name << endl;
}

void replace(string& in, string pattern, string replacement) {
   int position = in.find(pattern);
   while (position != -1) {
      in.replace(position, replacement.length(), replacement);
      position = in.find(pattern);
   }
}
 

blutaermer

Ingrid Marie
Registriert
31.12.03
Beiträge
273
sowohl dein als auch mein code haben funktioniert - leider war der kontext falsch. ausserdem ist dein code huebscher. danke.
 

tjp

Altgelds Küchenapfel
Registriert
07.07.04
Beiträge
4.059
das klappt auch ganz gut mit dem gemeinen punkt ('.'). mit dem dollarzeichen ('$') und dem leerzeichen (' ') jedoch nicht.

So, ich habe mal das ganze etwas umgeschrieben, damit es besser aussieht.

Code:
#include <string>
#include <ostream>
#include <iostream>

int main () {
	std::string name = "Dies.ist.ein.String.in.C++";
	std::string::size_type found;

	std::string str_point = ".";
	std::string newString = "$$";

	std::cout << "String =>" << name << "<=\n";

	do {
		found = name.find (str_point);
		if (std::string::npos != found) {
			name.replace (found, str_point.length(), newString);
		}
	} while (std::string::npos != found);
	
	std::cout << "String =>" << name << "<=\n";
}
 

Mitglied 7974

Gast
Man könnte jetzt natürlich eine Diskussion entfachen und die Frage stellen, ob es überhaupt möglich ist, in C++ "schönen" Code zu produzieren… ;)
 

Peter Maurer

Pommerscher Krummstiel
Registriert
16.03.04
Beiträge
3.077
Halb OT: Mir grimmt immer der Magen, wenn ich mich gezwungen sehe, dieselbe Zeile zweimal zu schreiben. Das finde ich naemlich nicht schoen. Und diese Abneigung fuehrt dann mitunter zu Konstrukten wie diesem aus snoopysalives Beispielquelltext abgewandelten Beispiel:

Code:
void replace(string& in, string pattern, string replacement) {
   int position;
   while ((position = in.find(pattern))>=0) {
      in.replace(position, replacement.length(), replacement);
   }
}
Kann jemand von Euch diese meine Nur-einmal-schreib'-Vorliebe nachvollziehen? :D
 

tjp

Altgelds Küchenapfel
Registriert
07.07.04
Beiträge
4.059
Kann jemand von Euch diese meine Nur-einmal-schreib'-Vorliebe nachvollziehen? :D
Bedingt ja, aber wenn man Funktionen schreibt, dann sollte man auf einige Dinge achten.

P.S. Deine Funktion ist fehlerhaft gewesen.
Code:
void replace(string& in, string const& pattern, string const& replacement) {
   std::string::size_type position (0);
   while (std::string::npos != (position = in.find(pattern))) {
      in.replace(position, replacement.length(), replacement);
   }
}
 

Skeeve

Pomme d'or
Registriert
26.10.05
Beiträge
3.120
Halb OT: Mir grimmt immer der Magen, wenn ich mich gezwungen sehe, dieselbe Zeile zweimal zu schreiben. [...] Kann jemand von Euch diese meine Nur-einmal-schreib'-Vorliebe nachvollziehen? :D
Aber hundertpro! und ich bin so froh, daß ich nicht in einer Sprache programmieren muß, in der man gezwungen ist, Strings in Schleifen zu behandeln!
Code:
$in=~ s/\./$$/g;
und gut is.

Und wenn man, wie Ursprünglich gefordert, viele Teilstrings ersetzen will, dann kommt man mit einem Hash weiter. Aber das führt jetzt zu weit.
 

Peter Maurer

Pommerscher Krummstiel
Registriert
16.03.04
Beiträge
3.077
@tjp: Mir ging's um's Prinzip! :D

Deshalb hab' ich das snoopysalive-Beispiel nur angeglichen, ohne ueber den Inhalt bzw. die Funktionsfaehigkeit gross nachzudenken. Und als Cocoa-verwoehnter Objective-C-Hansel hab' ich den Umgang mit diesen Sachen quasi verlernt, kenne mich also zu wenig aus, um Variablentypenfehler auf Anhieb zu erkennen. Das wuerde mir im Zweifel der Compiler sagen. ;)

(Koennte es wohl sein, dass "std::string::size_type" nichts anderes als ein verkapptes "int" ist?)

--

@Skeeve: Ja. Tatsaechlich begegnen mir solche Faelle auch selten bei der String-Behandlung, sondern meist beim Umgang mit anderen -- sagen wir mal: -- Ansammlungen, z.B. NSIndexSet.
 

tjp

Altgelds Küchenapfel
Registriert
07.07.04
Beiträge
4.059
Und als Cocoa-verwoehnter Objective-C-Hansel hab' ich den Umgang mit diesen Sachen quasi verlernt,
Auch unter diesem Gesichtspunkt war der Fehler vermeidbar. Denn unter dem Aspekt 64Bit sauberes Programm darf man so auch nicht in Objective-C programmieren.

Reden wir mal nur über UNIX Systeme, und lassen alle anderen außen vor.
UNIX definiert die 32Bit Laufzeitumgebung als ILP32 und die 64Bit Laufzeitumgebung als LP64.
=> "int" ist immer 32Bit groß
=> size_t ist entweder 32Bit oder 64Bit groß
=> SIZE_MAX ist der größte gültige Wert für size_t Variablen und wird in <stdint.h> definiert, und in der Single UNIX Spec steht nur, daß 65535 der minimale Wert für SIZE_MAX ist.

=> SIZE_MAX und INT_MAX können unterschiedlich groß sein. Nach meiner Erfahrung ist das bei einer 64Bit Laufzeitumgebung immer der Fall.


std::string::npos ist üblicherweise als der MAX Wert des Typs std::string::size_type definiert. Die Abfrage auf "… >= 0" war also fehlerhaft.
(Koennte es wohl sein, dass "std::string::size_type" nichts anderes als ein verkapptes "int" ist?)
Leider nein, das ist meistens mit size_t identisch, aber auch darauf darf man sich nicht verlassen, und das ist vor allem gültig, wenn man erlaubt std::basic_string<charT,traits,Allocator> zu übergeben. Denn in so einem Fall kann man std::basic_string<>::size_type beliebig selbst definieren.
 
Zuletzt bearbeitet:

Mitglied 7974

Gast
(...) Mir grimmt immer der Magen, wenn ich mich gezwungen sehe, dieselbe Zeile zweimal zu schreiben. (...)
Kann jemand von Euch diese meine Nur-einmal-schreib'-Vorliebe nachvollziehen? :D

Ich mag C++ nicht, weshalb es mir, ehrlich gesagt, egal war, ob in meinem Beispielcode eine Zeile doppelt auftauchte. Ich bin da zwar deiner Meinung, aber bevor ich nochmal fünf Minuten mehr daran herumgefuhrwerkt hätte, um herauszufinden, wie ich in C++ if-Statements besonders geschickt artikuliere, um damit Zeilen zu sparen (wie erwähnt, ich bin kein C++-Guru), war's mir lieber, Beispielcode Beispielcode sein zu lassen. Wichtig war ja nur, dass das Beispiel funktionierte.

(...) und ich bin so froh, daß ich nicht in einer Sprache programmieren muß, in der man gezwungen ist, Strings in Schleifen zu behandeln! (...)

Da sprichst du mir von der Seele. (Auch wenn ich Perl nicht besonders mag. ;))
 

tjp

Altgelds Küchenapfel
Registriert
07.07.04
Beiträge
4.059
Wichtig war ja nur, dass das Beispiel funktionierte.
Er ist falsch, warum kannst Du in der Antwort an Peter Maurer nachlesen. Es war "undefiniertes Verhalten" falls Dir das etwas sagt. Du hättest die 5 Minuten aufwenden sollen, den Code sauber zu formulieren.
Da sprichst du mir von der Seele. (Auch wenn ich Perl nicht besonders mag. ;))
C++ zählt nicht dazu. Wenn man boost::regex nicht kennt, dann ist das Eigenverschulden und man kann das der Programmiersprache nicht anlasten.
 

Skeeve

Pomme d'or
Registriert
26.10.05
Beiträge
3.120
C++ zählt nicht dazu. Wenn man boost::regex nicht kennt, dann ist das Eigenverschulden und man kann das der Programmiersprache nicht anlasten.
Oh! Ich habe C++ vor 13 Jahren mal benutzt (benutzen müssen) und damals war das noch kein Sprachstandard in C++. Ich wußte nicht, daß sowas inzwischen automatisch dazugehört. Verzeih meine Unwissenheit.
 

blutaermer

Ingrid Marie
Registriert
31.12.03
Beiträge
273
wusste ich auch nicht. ausserdem finde ich die datei regex.hpp auf meinem rechner nicht ...
 

tjp

Altgelds Küchenapfel
Registriert
07.07.04
Beiträge
4.059
Oh! Ich habe C++ vor 13 Jahren mal benutzt (benutzen müssen) und damals war das noch kein Sprachstandard in C++. Ich wußte nicht, daß sowas inzwischen automatisch dazugehört. Verzeih meine Unwissenheit.
Also, vor 13 Jahren gehörte noch nicht einmal std::string zu C++ offiziell dazu. Damals waren Bjarne Stroutrups C++ Bücher die offizielle Sprachreferenz. Es gab damals die Standard Template Library (STL) von SGI als Erweiterung von Stroustrups C++, diese diente dann als Grundlage für Template Anteile der Standard Library der ISO Norm: ISO 14882:1998 (die erste ISO Norm von C++). Desweiteren waren schon Drafts der ISO Norm im Umlauf bzw. die Compilerhersteller setzen diese um. Im Jahr 2003 wurde dann eigentlich nur ein "Technical Corrigendum 1" (ein TC darf nur Fehler in der Norm korrigieren, aber keinerlei Erweiterungen definieren) heraus gegeben, was aber wegen der Regel für die Überarbeitung von ISO Normen als ISO 14882:2003 verabschiedet wurde.

Weil man den zum Teil sehr stürmischen Entwicklungen anderer Programmiersprachen nicht nachstehen wollte, diese sich aber nicht mit einem ISO Normierungsverfahren vertragen, hat man beschlossen sinnvolle Erweiterung von C++ zukünftig im Rahmen eines eigenen inoffiziellen (im Sinne ist kein Teil der ISO Norm) Projektes umzusetzen. Boost war geboren. Die Boost Projekte stehen qualitativ den Standard Bibliotheken (im Englischen wird leider sprachlich nicht zwischen Standard und Norm unterschieden) anderer nicht normierter Programmiersprachen in nichts nach. Man kann also vollkommen gefahrlos auf diese zurückgreifen.

Mittlerweile wird tatkräftig an einer neuen Auflage der ISO Norm gearbeitet. Es gibt schon einen sogenannten "Technical Report 1" (TR1), der als Diskussiongrundlage für die neue Auflage dient. Es werden darin einige der Boost Bibliotheken als Basis für Erweiterungen benutzt, unter anderem wird es eine std::regex Bibliothek geben, die auf boost::regex basiert.

Es empfiehlt sich daher erstmal zu schauen, was die ISO Norm an Möglichkeiten bietet, wenn das nicht ausreicht sollte es selbstverständlich sein erstmal den Blick auf Boost zurichten.
 

Amin Negm-Awad

Süsser Pfaffenapfel
Registriert
01.03.07
Beiträge
665
Auch unter diesem Gesichtspunkt war der Fehler vermeidbar. Denn unter dem Aspekt 64Bit sauberes Programm darf man so auch nicht in Objective-C programmieren.
Man darf das so in Objective-C ganz gewiss nicht so programmieren, weil es ja C++-Code ist. :)
In Objective-C/Cocoa wäre der Fehler übrigens gar nicht passiert:
-replaceOccurrencesOfString:withString:oops:ptions:range: (NSMutableString)

Du meintest aber mutmaßlich den Fehler in der while-Bedingung. Das hat aber nichts mit 64-Bit-sauberen Programmen zu tun, sondern damit, dass es ein Define mit NSNotFound gibt. Dieses ist zu verwenden, bei 32 Bit wie bei 64 Bit.

Der Wert ist übrigens architekturabhängig, so dass er sich auf beiden Plattformen gleich "anfühlt" (aka der höchste positive Wert ist).

Daraus folgt auch, dass der Code auch auf einer 32-Bit-Plattform mindestens unsauber wäre und mutmaßlich nicht funktionieren würde. Mit 64 Bit hat das also nichts zu tun.

Und ja, ich kann Peters Aussage nachvollziehen: Derlei Ungetüme sind mir seit der alltäglichen Arbeit mit Objective-C auch fremd geworden.
 

Amin Negm-Awad

Süsser Pfaffenapfel
Registriert
01.03.07
Beiträge
665
Die Boost Projekte stehen qualitativ den Standard Bibliotheken (im Englischen wird leider sprachlich nicht zwischen Standard und Norm unterschieden) anderer nicht normierter Programmiersprachen in nichts nach. Man kann also vollkommen gefahrlos auf diese zurückgreifen.
Meines Wissens gibt es bis heute keine vollständig standardkonforme Toolchain für C++. Du bist da mehr auf der Höhe der Zeit. Gibt es eine?

Ansonsten bringt einen der Standard ja nichts, wenn man ihn nicht umsetzen kann. Das mag übrigens mit den keineswegs stets sinnvollen, sondern meist schlicht verkomplizierenden Erweiterungen von C++ zusammenhängen.
 

tjp

Altgelds Küchenapfel
Registriert
07.07.04
Beiträge
4.059
EDG hat die ISO Norm in ihrem C++ Frontend komplett umgesetzt. Von EDG gibt es nur das Frontend, der Kunde ist in diesem Fall ein Compileranbieter, und muß sein eigenes Backend verwenden. Es wird von vielen kommerziellen Compileranbietern verwendet. Der Comeau Compiler hat als erstes das konforme Frontend verwendet. Wann das genau war, muß man in den Release Notes nachlesen, es ist schon einige Jahre her. Bei den anderen Anbietern hat es wegen Kompatibilitätsgründen etwas länger gedauert bis sie die neuste EDG Version eingesetzt haben. Von Dinkumware gibt es die notwendigen C und C++ Libraries, damit der Compiler Norm konform wird.

g++ ist ziemlich nah an der ISO Norm dran, es fehlen einige sehr selten genutzt Features. Mir fällt spontan nur das Schlüsselwort "export" ein, auf das man aber relativ leicht verzichten kann.
 
Zuletzt bearbeitet:

tjp

Altgelds Küchenapfel
Registriert
07.07.04
Beiträge
4.059
Du meintest aber mutmaßlich den Fehler in der while-Bedingung. Das hat aber nichts mit 64-Bit-sauberen Programmen zu tun,
Der Fehler besteht darin, daß man mit einem "int" nicht garantiert alle Elemente in einem Array erreichen kann. Wie der Zufall so will, funktioniert es unter MacOS X 32Bit, so daß man mit einem "int" als Schleifentyp alle Elemente des Array erreichen kann.

Code:
// folgender Code ist falsch, da er nicht garantiert, 
// daß jedes Element des Array p erreicht wird

void for_each (char* p) {
    for (int i = 0; 0 != p[i]; ++i) {
        // mach irgend was
    }
}

Wenn man das auf einem 64Bit System macht, dann hofft man darauf, daß das Array nicht mehr als 2^31 Felder hat. Das erinnert mich an "640k is enough". Angesichts der Tatsache, daß es Rechner mit >1TB linearem RAM gibt, ist das sehr gewagt.
Und ja, ich kann Peters Aussage nachvollziehen: Derlei Ungetüme sind mir seit der alltäglichen Arbeit mit Objective-C auch fremd geworden.
Eine simple Schleife mit einem Funktionsaufruf über ein Feld zu iterieren, bezeichne ich nicht als Ungetüm. Notfalls schreibt man sich ein Standard Library kompatibles find_replace_all.

Nachfolgend wie man es mit boost:regex macht.
Code:
#include <string>
#include <ostream>
#include <iostream>
#include <sstream>

#include <boost/regex.hpp>

int main () {
  std::string name = "Dies.ist.ein.String.in.C++";
  std::cout << "String =>" << name << "<=\n";

  // Ausgabestrom und Iterator darauf vorbereiten
  std::ostringstream t;
  std::ostream_iterator<char, char> oi(t);

  // regex_replace ausführen
  // Das dämliches Scrollfeld
  // erfordert diesen Zeilenumbruch :-( 
  boost::regex_replace(oi, name.begin(), name.end(),
      boost::regex("\\."), "\\$\\$",
      boost::match_default);


  std::cout << "String =>" << t.str() << "<=\n";
}
 
Zuletzt bearbeitet: