Forum: PC-Programmierung alle "," durch "." eines strings ersetzen (in C)


von Reinhard L. (leiti7)


Lesenswert?

Hallo leute!

Versuche seit einigen Stunden vergeblich zu einer Lösung meines Problems 
zu kommen. Aber was ich auch probiert habe, es funktioniert nicht.
Ich hoffe von euch kann mir wer helfen?

Hier mein Problem:

Ich lese eine Datei zeilenweise ein, und speichere jede zeile immer in 
ein Array. in dieser Datei werden allerdings alle Kommazahlen mit einem 
"," geschrieben. Damit das C-Programm diese als Kommazahlen erkennt muss 
ich nun alle "," durch "." ersetzen.

sollte das nicht so funktionieren:

char Line[120] = "eingelesene,Zeile";

Line = Line.Replace("," , ".");

Bei mir funktioniert das jedenfalls nicht könnte mir da jemand 
weiterhelfen und mir eine andere Methode zeigen oder mich auf meine/n 
Fehler hinweisen.

Bitte berücksichtigt dass ich noch ein blutiger Anfänger bin was 
C-Programmierung angeht.

mfg. Reini

von Random .. (thorstendb) Benutzerseite


Lesenswert?

1
void Replace(char *pStr, char replace, char newChar)
2
{
3
  do {
4
    if(*pStr == replace) *pStr = newChar;
5
  } while(*pStr++);
6
}
7
8
unsigned int Replace2(char *pStr, char replace, char newChar)
9
{
10
  unsigned int cnt=0;
11
  do {
12
    if(*pStr == replace) {
13
      *pStr = newChar;
14
      cnt++;
15
    }
16
  } while(*pStr++);
17
18
  return(cnt);
19
}
20
21
void main() 
22
{
23
  char text[120] = "eingelesene,Zeile";
24
  unsigned int ret;
25
26
        Replace (text, ',', '.');
27
  ret = Replace2(text, ',', '.');
28
}

Bittesehr.

> Ich lese eine Datei zeilenweise ein, und speichere jede zeile immer
> in ein Array.
Musst du nicht, Kannst auch nen ret = fread(...) machen, da stehen dann 
die Newlines als CR, LF oder CRLF drin.
Zum Ersetzen von Zeichen ist das völlig unerheblich, und du bist damit 
schneller.

von Reinhard L. (leiti7)


Lesenswert?

Danke erstmlal.

Ich werde nun mal versuchen das umzusetzen.

von Applaus (Gast)


Lesenswert?

Hallo Reini,

verwechselst du gerade C und C#?
Was du da vor hast, geht nicht. Line ist ein Array aus chars und kennt 
daher keine Methode "Replace".

Hier eine kleine Funktion, mit der du das machen kannst:
1
void replace_char (char *s, char find, char replace)
2
{
3
  while (*s != 0)
4
  {
5
    if (*s == find)
6
      *s = replace;
7
    s++;
8
  }
9
}

Der Aufruf in deinem Fall:
1
replace_char (Line, ',' , '.');

VG
Thomas

von Helfer (Gast)


Lesenswert?

Reinhard Leitgeb schrieb:
> sollte das nicht so funktionieren:
>
> char Line[120] = "eingelesene,Zeile";
> Line = Line.Replace("," , ".");

Das ist kein C, sondern C++ oder eine andere objektorientierte Variante.

In Standard C würdest du eine Funktion selbst schreiben (so wie 
Thorsten) und ggf. Funktionen aus der Standardbibliothek /string.h/ 
verwenden.

> Bei mir funktioniert das jedenfalls nicht könnte mir da jemand
> weiterhelfen und mir eine andere Methode zeigen oder mich auf meine/n
> Fehler hinweisen.

Was sagt denn dein Compiler zu deinem Code???

> Bitte berücksichtigt dass ich noch ein blutiger Anfänger bin was
> C-Programmierung angeht.

Kein Problem, wir haben alle mal klein angefangen. Was ich aber sehr 
empfehlen kann: Beginne mal mit einem Buch über C, wie dem Klassiker von 
K&R:

http://en.wikipedia.org/wiki/The_C_Programming_Language


MFG
Helfer

von Random .. (thorstendb) Benutzerseite


Lesenswert?

Du liesst deine Zeilen warscheinlich mit fscanf(...) ein. Bei einigen 
wenigen Daten ist das durchaus ok.
Ich habe einen XML Reader/Interpreter/Codegenerator geschrieben, und dem 
gleich mehrere Streams verpasst. Im Reader selbst brauche ich zwar alles 
zeichenweise, aber meine interne GetNextChar() stuppst einen Loader an, 
der sich die nächsten 5MB des Files automatisch reinzieht. Enormer 
Performancegewinn.
Hier geht es aber auch um 3-20MB/XML File, bzw. >500MB insgesamt.

Genauso verhält es sich mit meiner Ausgabe in Files. Ich dachte, dass 
Windows das Streaming von Files bereits selbst macht, aber das scheint 
nicht der Fall zu sein. Vielleicht kann man das auch irgendwie 
aktivieren, oder andere Funktionen nutzen, ka, ich bin bei fread/fwrite 
geblieben und mache die Bufferung selbst. In/Output "vernünftig" zu 
buffern bringt nen enormen Performanceschub.

von Reinhard L. (leiti7)


Lesenswert?

>Was sagt denn dein Compiler zu deinem Code???

Ich bekomme folgende Fehlermeldung:

error C2228: left of '.Replace' must have class/struct/union type

Wisst ihr zufällig wie ich dieses problem behandeln soll?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Random ... schrieb:
> Du liesst deine Zeilen warscheinlich mit fscanf(...) ein.

Warum sollte man das tun? Mit fgets() kann man problemlos zeilenweise 
le_s_en (ein s).

von Martin (Gast)


Lesenswert?

den Aufwand  kannst Du DIr sparen.

google mal  unter 'c++ culture'   ,   da wird Dir  gezeigt wie
amerikanische Zahlen  ( mit  .  halt ) in einem 'deutschen' Programm 
eingelesen werden können , das deutsche  Programm verlangt hat  ',' .

von Random .. (thorstendb) Benutzerseite


Lesenswert?

Rufus Τ. Firefly schrieb:
> Random ... schrieb:
>> Du liesst deine Zeilen warscheinlich mit fscanf(...) ein.
>
> Warum sollte man das tun? Mit fgets() kann man problemlos zeilenweise
> le_s_en (ein s).

Reinhard Leitgeb schrieb:
> Bitte berücksichtigt dass ich noch ein blutiger Anfänger bin was
> C-Programmierung angeht.

deshalb :-)
printf und scanf sind idR. die ersten IO Funktionen, die man beim Lernen 
von C "zu Gesicht" bekommt.
Oder halt cin/cout, wobei ich mich mit den Dingern nie anfreunden 
konnte. Die sind ja auch C++, wobei C/C++ vielfach 
durcheinanderzermischt wird...

Ich bevorzuge fread/fwrite BIN/ASCII, je nach Bedarf :-)

von Random .. (thorstendb) Benutzerseite


Lesenswert?

Martin schrieb:
> den Aufwand  kannst Du DIr sparen.
>
> google mal  unter 'c++ culture'   ,   da wird Dir  gezeigt wie
> amerikanische Zahlen  ( mit  .  halt ) in einem 'deutschen' Programm
> eingelesen werden können , das deutsche  Programm verlangt hat  ',' .

Du kannst das auch mit Klassen in C++ realisieren, z.B. mit CString 
unter MS VC. CString bringt dann glaub ich auch so replacer mit. Benutze 
ich aber nicht, ist mir alles zu langsam und zu viel Overhead :-)

von Yalu X. (yalu) (Moderator)


Lesenswert?

Reinhard Leitgeb schrieb:
> Wisst ihr zufällig wie ich dieses problem behandeln soll?

So wie Random ... in seinem ersten Beitrag geschrieben hat: Schreib
Replace als Funktion, bei der der zu bearbeitende String als Argument
übergeben wird.

Übrigens kannst du dir auch mal die Funktion setlocale der C-Standard-
bibliothek anschauen. Damit kannst du das Verhalten von scanf,
printf usw. landesspezifisch einstellen. Das ist vor allem dann
sinnvoll, wenn die Datei mit den Kommata als Dezimaltrennzeichen auf dem
gleichen PC erstellt wird, auf dem auch dein C-Programm läuft. Mit
1
  setlocale(LC_ALL, "");

wird das vom Benutzer als Default definierte Locale (in Windows Länder-
einstellungen), also u.a. auch das richtige Dezimaltrennzeichen für Ein-
und Ausgaben verwendet. Auch das Datumsformat, die Sortierreihenfolge
von Strings uvw. werden davon beeinflusst.

Sollen allerdings nur beim Einlesen von Zahlen (nicht bei der Ausgabe)
Kommata als Dezimaltrennzeichen verwendet werden, und ist sicherge-
stellt, dass wirklich jedes in der Datei vorkommende Komma ein Dezi-
maltrennzeichen ist, ist die Konvertierung mit der /Replace/-Funktion
praktischer, weil sie unabhängig vom eingestellten Locale funktioniert
und sowohl Kommate als auch Punkte zulässt.

Random ... schrieb:
> Im Reader selbst brauche ich zwar alles zeichenweise, aber meine
> interne GetNextChar() stuppst einen Loader an, der sich die nächsten
> 5MB des Files automatisch reinzieht.

Das ist eigentlich genau das, was die Funktionen fread, fscanf, fgetc
usw. sowieso schon tun, deswegen werden sie auch von "buffered I/O
functions" genannt. Evtl. musst du mit setvbuf die Puffergröße und
-charakteristik deinen Wünschen anpassen.

von rackandboneman (Gast)


Lesenswert?

Schau Dir an was deine Umgebung an "Regular 
Expressions"-Funktionalitäten im Angebot hat, das ist eines der 
Werkzeuge die man kennen sollte wenn man viel mit Textdaten hantieren 
muss. Sonst gibt es auch noch eine freie Bibliothek namens PCRE...

von Random .. (thorstendb) Benutzerseite


Lesenswert?

Yalu X. schrieb:
> Das ist eigentlich genau das, was die Funktionen fread, fscanf, fgetc
> usw. sowieso schon tun, deswegen werden sie auch von "buffered I/O
> functions" genannt. Evtl. musst du mit setvbuf die Puffergröße und
> -charakteristik deinen Wünschen anpassen.

Stimmt, da war was :-)
Da hab ich mich beim retargeting der ARM <stdio> auf ein eigenes 
virtuelles Filesystem mal mit rumgeärgert **g** Beim retarget-Ziel 
"UARTn" soll der ja nicht buffern, sondern jedes Zeichen rausschieben 
ans Terminal.

Trotzdem bleib ich bei meinem eigenen Buffer, der ist "dichter dran" und 
einfacher anzupassen :-)

von Karl H. (kbuchegg)


Lesenswert?

Reinhard Leitgeb schrieb:

> Ich bekomme folgende Fehlermeldung:
>
> error C2228: left of '.Replace' must have class/struct/union type
>
> Wisst ihr zufällig wie ich dieses problem behandeln soll?

Indem du dir überlegst, dass es in C keine Klassen und daher auch keine 
Methoden innerhalb von Klassen gibt. Etwas von der Form a.b (welches 
keine Gleitkommazahl ist), kann in C nur eine Struktur sein. a ist der 
Variablenname der Struktur und b ist der Name der gewünschten Komponente 
der Struktur.

Hast du eine Struktur?

Nein! Du hast ein Array. Also kann die Syntax  Line.Replace schon mal 
nicht richtig sein.


Wie du dieses Problem behandeln sollst?
Indem du jetzt endlich einmal anfängst ein C-Buch von vorne bis hinten 
durchzuackern! Das ist ja nicht das erste mal, dass du hier eklatantes 
Nichwissen von absoluten Grundlagen zeigst und es wurde dir schon oft 
genug nahegelegt, dass du mit dem Lesen eines Buches anfangen musst. Tu 
es endlich! Du wirst aus deinem Viertelwissen nie herauskommen, wenn du 
nicht anfängst, dir die Sprache, ihre Möglichkeiten und ihre Syntax 
systematisch beizubringen. Durch immer wieder Aufschnappen von Brocken 
in Foren wird das nichts werden. Das hat noch bei keinem Neuling 
funktioniert und bei dir funktioniert es erst recht nicht.

> Bitte berücksichtigt dass ich noch ein blutiger Anfänger
> bin was C-Programmierung angeht.

Eine Zeitlang kriegst du diesen Bonus. Aber irgendwann ist schluss. 
Irgendwann heißt es dann: Warum tust du eigentlich nicht, was dir schon 
viele nahegelegt haben?
Wer einmal als Flachlandtiroler mit Sandalen in die Berge geht und von 
der Bergwacht gerettet werden muss, hat einen gut. Wer es aber ständig 
tut, muss damit rechnen, dass ihn dieses Verhalten irgendwann als 
"resistenter Wiederholungstäter" teuer kommt.


Das andere, was ich aus der Fehlermeldung herauslesen kann: Du 
verwendest einen C++ Compiler. Man kann einen C++ Compiler als eine Art 
'besseren C-Compiler' benutzen, wenn man sich bewusst ist, dass es im 
'C-Teil' von C++ Unterschiede zu C gibt. Dessen ist man sich aber nur 
dann bewusst, wenn man C auch wirklich beherrscht. Daher ist es für 
Anfänger allemal besser, erst einmal mit einem richtigen C-Compiler an 
die Sache heranzugehen und nicht von einem C++ Compiler nur den 'C-Teil' 
zu benutzen.

von rackandboneman (Gast)


Lesenswert?

http://blog.plover.com/2006/09/11/ ziemlicher AHA-Effekt was C vs C++ 
angeht.

...


Ein anderes Gedankenspiel welches hilft C-Arrays zu verstehen: Warum 
sind a[i] und i[a] in C identisch?

von Robert L. (lrlr)


Lesenswert?

>a[i] und i[a] in C identisch?

(ich hab ja GOTT SEI DANK NIX mit C zu tun..)

was erwartest für Antwort:
weil a und i einfach zusammengezählt werden


stimmt aber vermutlich nur bei byte und char array...

bei einem array mit Integern wird es nicht funktionieren?!?

von Volker Z. (vza)


Lesenswert?

Robert L. schrieb:
> stimmt aber vermutlich nur bei byte und char array...

nein , denn i wird implizit zu (*)(i*sizeof(*a))  erweitert.

Danach werden die beiden Zeiger addiert.

Volker

von Robert L. (lrlr)


Lesenswert?

und deshalb kann ich a und i vertauschen?

das ist a ziemlich unwahrscheinlich weil IMHO der pointer auf das array 
z.b. mit z.B. 4 multipliziert werden würde  und man damit "irgendwo" 
ist..

und B

>sizeof(*a)

nachdem i ja "alles mögliche" sein kann (byte/word/int usw.)
wird, wenn man a und i vertauscht  aus sizeof(*a) (also sizeof(*i) wird) 
ja entweder 1, 2, 4 ...

man multipliziert also entweder mit 1, 2 oder 4
was nicht stimmen kann


würd mich jetzt also WIRKLICH interessieren, was ich da jetzt übersehen 
hab..

von rackandboneman (Gast)


Lesenswert?

http://manderc.manderby.com/operators/arrayelementoperator/index.php

Vermutlich hat der Compiler intelligent genug zu sein um nachzuhalten 
welcher Teil des Ausdrucks ein Pointer und welcher ein Integer ist. Bei 
einer Pointeraddition addiert man ja auch nicht zwei Pointer sondern 
Pointer und Integer.

Auch gut fürs C-Verständnis: Die Aufgabe aus dem K&R, eine Funktion zu 
schreiben die messen kann wieviel Byte ein Integertyp nun wirklich hat 
(IIRC nach dem 4. oder 5. Kapitel in der 2. Ausgabe).

von Robert L. (lrlr)


Lesenswert?

>der C Compiler intelligent

haha


>a[i] und i[a] in C identisch?

kann mir das jetzt jemand erklären oder nicht?

von Klaus W. (mfgkw)


Lesenswert?

Robert L. schrieb:
> kann mir das jetzt jemand erklären oder nicht?

In C ist -entgegen anderslautender Behauptungen- nicht alles erlaubt.

Erlaubt ist beispielsweise int+int, char+int, char+char etc..

Nicht erlaubt ist beispielsweise Zeiger+Zeiger.

Dagegen wieder erlaubt ist Zeiger+int ebenso wie int+Zeiger (wegen der
Kommutativität der Addition beide Versionen).
Dabei ist festgelegt, daß erstens ein Zeiger rauskommt, und zweitens
das Ergebnis sich ergibt, indem der int-Operand mit der Größe
dessen multipliziert wird, worauf der Zeiger zeigt, erhöht um den Wert
des Zeigers.
Und das eben unabhängig davon, ob der Zeiger vorne steht oder die int.

Damit ist geregelt, was Zeiger+int bewirkt, also ist damit auch klar,
was *(Zeiger+int) macht, ebenso wie das gleichwertige *(int+Zeiger).

Weiterhin ist eines[anderes] nur eine andere Schreibweise für 
*(eines+anderes).

Also steht zeiger[int] für *(zeiger+int) und int[zeiger] steht für
*(int+zeiger).
Beides ist nach obiger Regel aber gleichwertig.

von Robert L. (lrlr)


Lesenswert?

hey super
habs verstanden

wenigstens einer der sich in c auskennt, und nicht nur so tut als ob ;-)

>indem der int-Operand mit der Größe
>dessen multipliziert wird, worauf der Zeiger zeigt,

DAS war das was ich nicht wusste...

von Chocco (Gast)


Lesenswert?

Moin.
Hab das hier grad mal ein wenig überflogen.

Nur nochmal als kleine ergänzung:

Das "Zeiger + Zeiger" nicht erlaubt ist, ist so nicht ganz richtig.
Es gibt einfach keine praktisch sinnvolle Anwendung, weshalb man 2 
Zeiger addieren sollte. Deswegen wurde dies nicht implementiert.

und zu der ursprünglichen Frage / dem Ursprünglichen Problem:

"," durch "." ersetzen....

Gehe Das Array Zeichen für Zeichen durch und schaue ob das Zeichen 
ein"," ist. Wenn ja, dann ersetze "," durch ".", wenn nicht, lass das 
zeichen in ruhe.

Ich denke mal, das das Problem schon gelöst ist, trotzdem nochmal 
standard
C-Code dazu:
(Dies ist nur ein Beispiel mit einem vordefinierten Array! Der Code ist 
für ein Win32-Konsolenprojekt ausgelegt!)
1
#include <stdio.h>
2
#include <conio.h>
3
#include <windows.h>
4
5
void main ( void )
6
{
7
  // Varriablen Deklaration
8
  char sCharArray[23]="sd,f,h.sdlkfj,fsd,f.e.";  //Array
9
  int i;  //Schleifenzähler
10
11
  //Ausgabe des Arrays VOR der Bearbeitung
12
  printf("\n%s\n", sCharArray);
13
14
  //for-Schleife zum durchgehen des Arrays, Zeichen für Zeichen
15
  for( i=0 ; i<23 ; i++ )
16
  {
17
    //if-Anweisung zum überprüfen des Zeichens
18
    if( sCharArray[i] == ',' )
19
    {
20
      //Ersetze das "," durch "."
21
      sCharArray[i]='.';
22
    }
23
  }
24
25
  //Ausgabe des Arrays NACH der Bearbeitung
26
  printf("%s\n\n", sCharArray);
27
28
  //Das Schließen des Konsolenfensters verhindern
29
  system("pause");
30
}

Grüße Chocco

von Rolf Magnus (Gast)


Lesenswert?

Klaus Wachtler schrieb:
> Dabei ist festgelegt, daß erstens ein Zeiger rauskommt, und zweitens
> das Ergebnis sich ergibt, indem der int-Operand mit der Größe
> dessen multipliziert wird, worauf der Zeiger zeigt, erhöht um den Wert
> des Zeigers.

Das ist ja auch mit der Hauptgrund, warum es in C überhaupt Zeigertypen 
gibt.

Chocco schrieb:
> Das "Zeiger + Zeiger" nicht erlaubt ist, ist so nicht ganz richtig.

Doch, das ist richtig. Es ergibt auch keinen Sinn, weil ein Zeiger immer 
eine absolute Adresse darstellt. Das ist etwa so, als wolle man den 
3.5.2010 und den 24.10.2011 addieren. Man kann Tage zu einem Datum 
hinzuzählen, dann kommt man bei einem neuen Datum heraus, aber man kann 
kein anderes Datum dazuaddieren, weil das keinen Sinn ergibt. Man kann 
aber umgekehrt von einem Datum ein anderes abziehen und bekommt dann 
eine Differenz in Tagen. Und genau nach dem selben Prinzip verhalten 
sich auch Zeiger.

> Es gibt einfach keine praktisch sinnvolle Anwendung, weshalb man 2
> Zeiger addieren sollte. Deswegen wurde dies nicht implementiert.

Ähm, die Konseuqenz aus dieser Aussage wäre dann doch,
> Das "Zeiger + Zeiger" nicht erlaubt ist
oder?

von Robert L. (lrlr)


Lesenswert?

auch wenn es "nur" ein Beispiel ist, aber DAS macht man nicht:

for( i=0 ; i<23

(das 23 mein ich)

(IMHO sind in "good old" C  auch eher 0 terminierte "Strings" üblich 
(und keine array)

Außerdem leben wird im "Zeitalter" von unicode
da ist das Ganze nicht mehr so trivial..

von Klaus W. (mfgkw)


Lesenswert?

Das Beispiel ist eh ziemlich schrullig.
Es sind ja nur 22 Byte Nutzdaten im String, und die abschließende 0.
Trotzdem werden 23 Zeichen geprüft.

Und wie

> standard C-Code

und

> #include <windows.h>
...
> Win32-Konsolenprojekt
...
> system("pause");

zusammengehen, weiß ich auch nicht so recht.

von Uwe (Gast)


Lesenswert?

Nach der Fehlermeldung die er bekommt ist das kein C Compiler.

von Chocco (Gast)


Lesenswert?

Entschuldigt bitte, aber das, was ich da oben an Code gepostet habe 
wurde MIR, so wie es da steht, als Standard C-Code beigebracht! :(

Klärt mich doch bitte auf, wenn dies so nicht der wahrheit entsprechen 
sollte.

Und zu den Zeigern: Meine Aussage war falsch formuliert, und dafür 
entschuldige ich mich viel mals. Es sollte eigentlich nur eine ergänzung 
sein, warum Zeiger+Zeiger nicht erlaubt / möglich ist.

Entschludigt bitte mein unwissen, ich kann nichts dafür, das in 
Lehranstalten nur noch die halbe wahrheit erzählt wird. :(

von Klaus W. (mfgkw)


Lesenswert?

Chocco schrieb:
> Entschuldigt bitte, aber das, was ich da oben an Code gepostet habe
> wurde MIR, so wie es da steht, als Standard C-Code beigebracht! :(

Standard ist im Zweifelsfall, was im K&R oder im entsprechenen ISO-Blatt 
steht, je nach C-Version.
(Es sei denn, man folgt dem, was Microsoft als Standard gern hätte, dann 
ist das natürlich was anderes.)

Dazu gehört schon mal kein windows.h.

Weiterhin ist zwar system() eine Standardfunktion, aber was man an 
system() als Kommando übergeben kann und wie das dann funktioniert, ist 
schwer vom Betriebssystem bzw. der Umgebung des Programms abhängig.
PAUSE geht halt nur unter Windows, auf einem anderen System braucht man 
auch den ganzen Plunder mit system an der Stelle nicht.
Abgesehen davon, daß es mit Kanonen auf Spatzen geschossen ist, wenn man 
einen Kommandointerpreter startet, den ein Kommando ausführen lässt, was 
dann wieder auf eine Eingabe wartet, nur um das eigenen Programmende zu 
verzögern, bis der Benutzer Return tippt. Ein schnödes getchar() würde 
auf jedem System funktionieren (deklariert in stdio.h auf jedem System).

Chocco schrieb:
> Entschludigt bitte mein unwissen, ich kann nichts dafür, das in
> Lehranstalten nur noch die halbe wahrheit erzählt wird. :(

Du kannst nur etwas dafür, wenn du es unreflektiert weiter erzählst :-)
Den Rest der Wahrheit muß man immer selbst besorgen...

von Chocco (Gast)


Lesenswert?

Danke dir. werd´s mir merken :)

von Finsbury (Gast)


Lesenswert?

Zur eigentlichen Frage: Was spricht gegen
1
strrepl
 aus der Standard-C-Library?

von DirkB (Gast)


Lesenswert?

"strrepl" und "Standard-C-Library" passen nicht zusammen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.