Zum Inhalt springen

Knuddlbaer

Mitglieder
  • Gesamte Inhalte

    119
  • Benutzer seit

  • Letzter Besuch

Beiträge von Knuddlbaer

  1. [quäl]


    #include <string>
    #include <algorithm>
    #include <vector>
    #include <functional>

    namespace
    {
    void fillVec(std::vector<char> & vec,const std::string & from,const std::string & to)
    {
    vec.resize(256);

    for(int i = 0;i < 256;++i)
    vec[i] = i;

    std::string::const_iterator pos2 = to.begin();
    for(std::string::const_iterator pos = from.begin();pos != from.end() && pos2 != to.end();++pos,++pos2)
    vec[*pos] = *pos2;
    }
    }

    struct DeCode: std::unary_function<char,char>
    {
    std::vector<char> dec;
    unsigned long counter;

    DeCode(const std::string & from,const std::string & to) : counter(0)
    { fillVec(dec,from,to); }

    char operator()(char x) { return dec[x]; }
    };


    struct EnCode: std::unary_function<char,char>
    {
    std::vector<char> enc;
    unsigned long counter;

    EnCode(const std::string & from,const std::string & to) : counter(0)
    { fillVec(enc,to,from);}

    char operator()(char x) { return enc[x]; }
    };





    int main()
    {
    char *str1="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    char *str2="EPSTIWKNUVGCLRYBWHMDOFXQAG";

    EnCode enc(str1,str2);
    DeCode dec(str1,str2);

    std::string temp("HALLO WELT\n");

    std::transform(temp.begin(),temp.end(),temp.begin(),enc);
    std::cout<<temp;
    std::transform(temp.begin(),temp.end(),temp.begin(),dec);
    std::cout<<temp;
    }
    [/PHP]

    [/quäl]

  2. Original geschrieben von nic_power

    Hallo,

    warum so kompliziert? Wenn man - wie oben bereits erwähnt - die ASCII-Werte der chars direkt als Index in die Arrays verwendet, kann man sich die Suche nach dem passenden Char komplett sparen

    Stimmt... Viel zu kompliziert da oben :o(

    Nimmt man mal das was Du gemacht hast ins prädikat auf ist man noch genauso flexiebel (iteratoren...) , es schaut besser aus ist schlanker.... Naja, einfach besser :o)


    #include <string>
    #include <algorithm>
    #include <vector>
    #include <functional>

    struct DeCode: std::unary_function<char,char>
    {
    std::vector<char> dec;
    unsigned long counter;

    DeCode(const std::string & from,const std::string & to) : counter(0)
    {
    dec.resize(256);

    for(int i = 0;i < 256;++i)
    dec.push_back(i);

    std::string::const_iterator pos2 = to.begin();
    for(std::string::const_iterator pos = from.begin();pos != from.end() && pos2 != to.end();++pos,++pos2)
    dec[*pos] = *pos2;

    }

    char operator()(char x)
    { return dec[x]; }
    };


    struct EnCode: std::unary_function<char,char>
    {
    std::vector<char> enc;
    unsigned long counter;

    EnCode(const std::string & from,const std::string & to) : counter(0)
    {
    enc.resize(256);

    for(int i = 0;i < 256;++i)
    enc[i] = i;

    std::string::const_iterator pos2 = to.begin();
    for(std::string::const_iterator pos = from.begin();pos != from.end() && pos2 != to.end();++pos,++pos2)
    { enc[*pos2] = *pos; }

    }

    char operator()(char x)
    { return enc[x]; }
    };





    int main()
    {
    char *str1="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    char *str2="EPSTIWKNUVGCLRYBWHMDOFXQAG";

    EnCode enc(str1,str2);
    DeCode dec(str1,str2);

    std::string temp("HALLO WELT\n");

    std::transform(temp.begin(),temp.end(),temp.begin(),enc);
    std::cout<<temp;
    std::transform(temp.begin(),temp.end(),temp.begin(),dec);
    std::cout<<temp;
    }


    Allerdings stehe ich hier auch schon wieder in Versuchung das Füllen des vectors auszulagern und nurnoch den Vector zu übergeben. Dann noch nen Wrapper drum damit ich diesen Aufruf verstecke... Und bin bis auf die Map wieder da wo ich vorhin war :/
    [/PHP]

  3. Original geschrieben von FinalFantasy

    Also ehrlich gesagt kann ich mit dem Code selber nicht viel Anfangen.

    Hab mich eigentlich noch nicht mit Templates befasst.

    Ne Erklärung wär vielleicht auch nicht schelcht. :D


    #include <string>
    #include <map>
    #include <algorithm>
    #include <iostream>
    #include <fstream>

    //------------------------------------------------------------------------
    // Konvertiert mit Hilfe einer map x zu y wenn definiert
    //------------------------------------------------------------------------
    struct swapHelper : std::unary_function<char,char>
    {
    std::map<char,char> mymap;
    unsigned long counter;
    // Konstruktor.Nimmt eine map entgegen und kopiert sie lokal fürs weiterarbeiten
    // counter wird auf 0 gesetzt
    swapHelper(std::map<char,char> & yourmap) : counter(0) {mymap = yourmap;}


    char operator()(char x)
    {
    // Wenn für jedes vorkomemnde Zeichen etwas definiert ist:
    // return mymap[x];
    std::map<char,char>::iterator pos = mymap.find(x);
    if(pos == mymap.end()) // Wenn das Zeichen nicht in der Map steht
    return x; // original zurückgeben
    else // Ansonsten
    {
    ++counter; // den Zähler erhöhen
    return pos->second; // und das Zeichen durch das getauscht werden soll zurückgeben
    }
    }
    };


    // Das Konstrukt da oben wird für std::transform benötigt. In C wäre es einfach ein Funktionszeiger.
    // Da ich aber eine map brauche die mit die "Übersetzung" hält und ich einen Counter am ende
    // auslesen will habe ich eine Klasse genommen die im Konstruktur die map bekommt und mir
    // den Counter zählt.
    // std::transform ruft den operator() auf von dem was es übergeben bekommt.Somit kommt
    // char operator()(char x) ins Spiel.
    // Das ganze von std::unary_function abgeleitet ermöglicht es einfach in Tranform zu verwenden.
    // Das könnte dem Objekt auch noch massig Funktionen dazu geben und es detailliert Informieren
    // wann es was zu tun hat.


    //------------------------------------------------------------------------
    // Baut aus zwei strings eine map auf
    //------------------------------------------------------------------------
    std::map<char,char> strToCharMap(const std::string & from,const std::string & to)
    {
    using namespace std;

    map<char,char> temp;
    string::const_iterator pos = from.begin();
    string::const_iterator pos2 = to.begin();

    // Über beide Strings laufen bis einer das ende Erreicht hat
    // (std::string hört nicht bei \0 auf)
    for(;pos != from.end() && pos2 != to.end();++pos,++pos2)
    temp.insert(make_pair(*pos,*pos2)); // Wertepaar speichern

    return temp;
    }
    // Mir ist keine rechte Idee gekommen wie ich die 2 Arrays verwende
    // Eine map hält ein Wertepaar das in einem Suchbaum gehalten wird.
    // Ich investiere hier die Zeit jedes Zeichen der 2 Strings als Wertepaar zu speichern.
    // Erleichtert mir später die Arbeit mit suchen und ersetzen.



    //------------------------------------------------------------------------
    // Tauscht die in einer map stehenden Zeichen aus mit hilfe von iteratoren
    //------------------------------------------------------------------------

    template<typename BegIn,typename EndIn,typename BegOut>
    long swapChars(const BegIn & beg,const EndIn & end,const BegOut & out,const std::string & from,const std::string & to)
    {
    using namespace std;

    if(from.size() != to.size())
    return -1;

    map<char,char> myMap(strToCharMap(from,to)); // Map erzeugen und Compileroptimierung ausnutzen.
    // hier wird keiner map erstellt.
    // Anlegen des swapHelpers mit unserer Übersetzungstabelle
    swapHelper swhlp(myMap); // Würde man swapHelper swhlp(strToCharMap(from,to)); schreiben
    // könnte der Compiler die map gleich im Objekt erstellen

    // Und nun jedes einzelne Zeichen durch den swapHelper schicken
    std::transform(beg,end,out,swhlp);
    return swhlp.counter; // zurpückgeben wieviel Zeichen gezählt wurden
    }

    // Diese Routine macht die gleiche Arbeit wie Deine (mit ner menge Hilfe von aussen)
    // Als erstes wird auch hier die größe Überprüft (um kompatiebel zu bleiben mit Deiner Funktion)
    // Danach werden die Strings als Wertepaare gespeichert. (Spart später das immer wieder suchen der Zeichen)
    // Gefolgt wird das ganze vom Anlegen des swapHelpers.
    // Der kann auch so verwendet werden:: cout<<swhlp('H');
    // Dieser sorgt einfach nur dafür das H in irgendwas anderes gewandelt wird.
    // Im Konstruktor bekommt der swapHelper die map übergeben in der steht was passieren soll

    // tansform:
    // transform erwartet den Anfang und das Ende der Quelle, den Start des Ziels und einem Objekt
    // das etwas macht. Das Ziel muß dabei genug Platz bieten.
    // transform geht nun zeichen für zeichen so vor:
    // Nimm ein Zeichen von Source übergebe es an swhlp() und schreibe das Ergebnis in Dest
    // Danach dest und source ein Zeichen weiterstellen
    // mit tranfsorm(text.begin(),text.end(),text.begin(),ptr_fun(toupper));
    // könntest Du z.B. alle Zeichen in groß wandeln.

    // die Templates:
    // Die Templates sorgen dafür das man allerlei angeben kann. Der Compiler setzt den passenden Typen ein
    // durch die Templates wird es möglich iteratoren und zeiger zu verwenden.

    // iteratoren:
    // Eine Abstraktion von Zeigern die speziell auf eine Klasse angepasst sind.
    // Bei einer verketteten Liste wird zum nächsten Element gesprungen
    // bei einer Datei zum nächsten Zeichen...
    // Ähneln im prinzip sehr stark den Zeigern


    //------------------------------------------------------------------------
    //
    //------------------------------------------------------------------------
    template<typename BegIt,typename EndIt>
    long swapChars(const BegIt & beg,const EndIt & end,const std::string & from,const std::string & to)
    {
    return swapChars(beg,end,beg,from,to);
    }

    // Wenn jemand kein extra Ziel hat wird hier einfach in den gleichen Bereich zurückgeschrieben
    // aus dem gelesen wurde.

    //------------------------------------------------------------------------
    //
    //------------------------------------------------------------------------
    long swapChars(std::string & text,const std::string & from,const std::string & to)
    {
    return swapChars(text.begin(),text.end(),from,to);
    }

    // Wenn jemand einen std::string übergeben hat wird dieser mit seinen Iteratoren an die obrige
    // Methode gegeben.
    // Somit spart man sich das immer wieder neu schreiben der Methode.
    // Damit der Anwender aber nicht swapCharString swapChar2Iter swapChar3Iter etc. aufrufen
    // muss wurde das hier überladen. Zu beachten bei templates: Die überladungen müssen
    // vor der verwendung bekannt gemacht werden!

    //------------------------------------------------------------------------
    //
    //------------------------------------------------------------------------
    using namespace std;
    int main(int argc, char * argv[])
    {
    // String zum testen
    string temp("Hallo Welt");
    // Übersetzungsstrings
    string from(" EPSTIWKNUVGCLRYBWHMDOFXQAGepstiwknuvgclrybwhmdofxqag");
    string to (" ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");

    // Original auf dem Bildschrim ausgeben
    cout<<temp<<"\n";

    // Einen std::string als Basis nehmen
    // und diesen "Übersetzen"
    swapChars(temp,from,to);
    std::cout<<temp<<"\n";

    // Beliegige Iteratoren verwenden (hier std::string::iterator)
    // Hier wird gezeigt wie man iteratoren verwenden kann
    // z.B. könnte die Basis auch vector<char> sein oder list<char> o.ä.
    swapChars(temp.begin(),temp.end(),from,to);
    cout<<temp<<"\n";

    // Hier ein Beispiel geben wie man Zeiger verwenden kann
    // wenn man CString hat könnte man das z.B. so machen
    char temp2[] = "Hallo Welt";
    // dem Compiler helfen zu erkennen um welchen Typ es sich handelt
    // dann den Start und das Ende des zu bearbeitenden Bereichs angeben
    swapChars<char *,char *>(temp2,temp2+sizeof(temp2),from,to);
    std::cout<<temp2<<"\n";


    // Eine Datei zum lesen und eine zum schreiben öffnen (binär)
    ifstream in("t:\\in.txt",ios::in|ios::binary);
    ofstream out("t:\\out.txt",ios::out|ios::binary);

    //prüfen ob beide Dateien geöffnet sind
    if(!in || !out)
    return 20;

    // Ermöglicht es Dateien fast wie Zeiger zu verwenden
    // dieser Zeiger funktioniert aber nur in eine richtung!
    istreambuf_iterator<char> beg(in); // Erzeugt sowas wie einen virtuellen Zeiger der sich fast wie char* verhält
    istreambuf_iterator<char> end; // und an den Anfang der Datei zeigt. Wenn das ende der Datei erreicht ist wird einfach nur ein leerer "Zeiger" zurückgegeben
    ostreambuf_iterator<char> beg2(out);// das ganze noch mal für die Ausgabe datei

    // Die Datei kopieren und dabei übersetzen
    swapChars(beg,end,beg2,from,to);

    return 0;
    }

    [/PHP]

  4. Ich habe nirgens geschrieben das es Vorteile hat.

    Ich hab einfach Lust gehabt es mal nachzubauen. Da es vllt. in diesem Forum

    auch noch andere gibt die C++ programmieren, könnte es interesannt sein zu sehen was passiert.

    Ziel dabei war es:

    - Leichtes Umdefinieren der "Art" wie die Zeichen geändert werden (also leichtes Austauschen)

    - Einsatz von Iteratoren (soll heissen z.B. alles verwenden zu können byteweise verwendet werden kann)

    - Für mich persönlich mal wieder mit prädikaten zu üben

    - Für mich persönlich mal wieder mit algorithm zu arbeiten

    - vllt. etwas interesse an C++ zu wecken. (Allerdings lassen sich viele vom ersten Blick gleich abschrecken)

    Sicherlich ist der Code da oben NICHT anfängerfreundlich.

    Hat ja aber auch keiner behauptet:

    Mal ein bisschen C++ spielerei zu diesem Thema (kompletter Source)

    Damit sollten also die C++ Freaks angesprochen werden.

  5. Mal ein bisschen C++ spielerei zu diesem Thema (kompletter Source)

    auch wenns keiner wissen wollte :o)


    #include <string>
    #include <map>
    #include <algorithm>
    #include <iostream>
    #include <fstream>

    // Konvertiert x zu y. Wenn x nicht definiert ist wird x zurückgegeben

    //------------------------------------------------------------------------
    // Konvertiert mit Hilfe einer map x zu y wenn definiert
    //------------------------------------------------------------------------
    struct swapHelper : std::unary_function<char,char>
    {
    std::map<char,char> mymap;
    unsigned long counter;
    swapHelper(std::map<char,char> & yourmap) : counter(0) {mymap = yourmap;}

    char operator()(char x)
    {
    // Wenn für jedes vorkomemnde Zeichen etwas definiert ist:
    // return mymap[x];
    std::map<char,char>::iterator pos = mymap.find(x);
    if(pos == mymap.end())
    return x;
    else
    {
    ++counter;
    return pos->second;
    }
    }
    };

    //------------------------------------------------------------------------
    // Baut aus zwei strings eine map auf
    //------------------------------------------------------------------------
    std::map<char,char> strToCharMap(const std::string & from,const std::string & to)
    {
    using namespace std;

    map<char,char> temp;
    string::const_iterator pos = from.begin();
    string::const_iterator pos2 = to.begin();

    for(;pos != from.end() && pos2 != to.end();++pos,++pos2)
    temp.insert(make_pair(*pos,*pos2));

    return temp;
    }

    //------------------------------------------------------------------------
    // Tauscht die in einer map stehenden Zeichen aus mit hilfe von iteratoren
    //------------------------------------------------------------------------

    template<typename BegIn,typename EndIn,typename BegOut>
    long swapChars(const BegIn & beg,const EndIn & end,const BegOut & out,const std::string & from,const std::string & to)
    {
    using namespace std;

    if(from.size() != to.size())
    return -1;

    map<char,char> myMap(strToCharMap(from,to));
    swapHelper swhlp(myMap);

    std::transform(beg,end,out,swhlp);
    return swhlp.counter;
    }

    //------------------------------------------------------------------------
    //
    //------------------------------------------------------------------------
    template<typename BegIt,typename EndIt>
    long swapChars(const BegIt & beg,const EndIt & end,const std::string & from,const std::string & to)
    {
    return swapChars(beg,end,beg,from,to);
    }

    //------------------------------------------------------------------------
    //
    //------------------------------------------------------------------------
    long swapChars(std::string & text,const std::string & from,const std::string & to)
    {
    return swapChars(text.begin(),text.end(),from,to);
    }


    //------------------------------------------------------------------------
    //
    //------------------------------------------------------------------------
    using namespace std;
    int main(int argc, char * argv[])
    {
    string temp("Hallo Welt");
    string from(" EPSTIWKNUVGCLRYBWHMDOFXQAGepstiwknuvgclrybwhmdofxqag");
    string to (" ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");

    cout<<temp<<"\n";
    // Einen std::string als Basis nehmen
    swapChars(temp,from,to);
    std::cout<<temp<<"\n";

    // Beliegige Iteratoren verwenden (hier std::string::iterator)
    swapChars(temp.begin(),temp.end(),from,to);
    cout<<temp<<"\n";

    // Auch Zeiger sind möglich
    char temp2[] = "Hallo Welt";
    swapChars<char *,char *>(temp2,temp2+sizeof(temp2),from,to);
    std::cout<<temp2<<"\n";


    ifstream in("t:\\in.txt",ios::in|ios::binary);
    ofstream out("t:\\out.txt",ios::out|ios::binary);

    if(!in || !out)
    return 20;

    istreambuf_iterator<char> beg(in);
    istreambuf_iterator<char> end;
    ostreambuf_iterator<char> beg2(out);

    // Wenn man das Ziel extra angibt werden auch forwarditeratoren möglich
    swapChars(beg,end,beg2,from,to);

    return 0;
    }
    [/PHP]

  6. Angesichts der Tatsache das locales eingesetzt werden ist es nicht garantiert das isalnum in isprint enthalten ist. Ich sehe aber isspace als überflüssig an da dies wohl in isprint enthalten ist.

    Wenn Du die Beiträge nicht genauso oberflächlich lesen würdest wie ich würde Dir auffallen das es kein Source ist der auf das eigentliche Problem passt, sondern nur für den Fragenden eine Möglichkeit geben sollte sehr individuelle Regeln für das erkennen geben sollte. Es war einfach nur der Ausschnitt aus einem Source der innerhalb eines Projektes eine spezielle Aufgabe übernommen hat der für den damalig eingesetzten Compiler ein paar workarounds brauchte.

    Wenn Dir nun etwas daran gelegen wäre das jemand der den Code verwendet ein besseres Ergebnis hat, hätte da bestimmt ein neuer Vorschlag der Routine gestanden. So wurden nur Erbsen gezählt ohne die Zutaten der Verpackung gelesen zu haben.

    (btw wäre isascii mit isSonderzeichen eine brauchbare kombination, wobei ich isSonderzeichen heute anderst Implementieren würde. Hierbei wäre aber eventuell das Ergebnis falsch wenn isalnum in der verwendeten locale nicht in isascii liegen sollte)

    Der Source stellt eine Möglichkeit da geändert zu werden auf die persönlichen Bedürfnisse. Wer nicht will braucht den nicht nehmen.

  7. Original geschrieben von nic_power

    Hallo,

    die einzige zuverlässige und portable Lösung ist das komplette Abarbeiten der Datei in dem Du jedes einzelne Zeichen daraufhin überprüfst, ob es sich um ein ASCII-Zeichen handelt. C stellt dafür "isascii() & Friends" zur Verfügung.

    Nic

    Das berücksichtigt aber die Umlaute etc. nicht.

    Ich musste mal sowas in der Art programmieren.

    Ich habe dafür ein Funktionsobjekt erstellt das man nach belieben abändern kann.

    Viel spaß mim Source....


    // isascii.cpp : Definiert den Einstiegspunkt für die Konsolenanwendung.
    //

    #include "stdafx.h"
    #include <iterator>
    #include <iostream>
    #include <fstream>
    #include <algorithm>
    #include <functional>
    #include <locale>

    using namespace std;

    namespace
    {
    bool isUmlaut(char zeichen)
    {
    // korrigiere_signed_char(zeichen);
    return zeichen == 'ä' || zeichen == 'ö' || zeichen == 'ü'
    || zeichen == 'Ä' || zeichen == 'Ö' || zeichen == 'Ü';
    }

    bool isSonderzeichen(char zeichen)
    {
    // korrigiere_signed_char(zeichen);
    return isUmlaut(zeichen) || zeichen == 'ß';
    }


    }

    struct test : public unary_function<unsigned char,bool>
    {
    bool operator()(unsigned char i) const
    {
    static locale loc ( "German_Germany" );
    //return isalpha(i,loc);
    return isalnum(i,loc) || isspace(i,loc) || isprint(i,loc) || isUmlaut(i);;

    }
    };



    int main(int argc, char * argv[])
    {

    if(argc<2)
    {
    cout<<argv[0]<<"filename to test";
    return 20;
    }

    ifstream infile(argv[1],ios::in|ios::binary);
    if(!infile)
    {
    cout<<"can't open "<<argv[1];
    return 20;
    }

    istreambuf_iterator<char> beg(infile);
    istreambuf_iterator<char> end;
    istreambuf_iterator<char> pos;


    pos = find_if(beg,end,not1(test()));

    if(pos == end)
    cout<<"ascii";
    else
    cout<<"binary";

    return 0;
    }


    [/PHP]

  8. Zeig mal den source.

    Hast mal versucht nach char zu casten und sizeof(long) anzugeben ?

    Du könntest in einem eigenen Namensraum mithilfe eines Templates

    dafür sorgen das Du ein template hast das einen cast durchführt und die länge mit sizeof() ermittelt.

    Dann definierst Du einen operator<< und >> für Deine Klasse die sich wiederum der operator<<(T) bedient. Unnames namespaces würden sich anbieten.

  9. Oder man schaut es sich mal mit C++ an:

    Kompletter lauffähiger code:


    #include <stdlib.h>
    #include <time.h>
    #include <set>
    #include <iostream>
    using namespace std;

    int main(int argc, char * argv[])
    {
    // Set damit jede Zufallszahl nur einmal vorkommt
    set<int> zufall;
    srand((unsigned)time(0));

    // Solange laufen bis 10 unterschiedliche Zufallszahlen im set sind
    while(zufall.size()< 10)
    zufall.insert(rand());

    cout<<"Geben Sie bitte eine Zahl ein";


    // Hilfsausgabe das man auch mal die richtige Zahl erwischt beim testen ))
    copy(zufall.begin(),zufall.end(),ostream_iterator<int>(cout," "));


    // Benutzer nach Zahl fragen
    int suchzahl;
    cin>>suchzahl;

    // Und prüfen ob die vorhanden ist.
    if(zufall.find(suchzahl)!=zufall.end())
    cout<<"\nIhre Zahl war vorhanden";
    else
    cout<<"\nIhre Zahl war NICHT vorhanden";



    return 0;
    }
    [/PHP]

  10. Sets a random starting point.

    void srand(

    unsigned int seed

    );

    Parameters

    seed

    Seed for random-number generation

    Remarks

    The srand function sets the starting point for generating a series of pseudorandom integers. To reinitialize the generator, use 1 as the seed argument. Any other value for seed sets the generator to a random starting point. rand retrieves the pseudorandom numbers that are generated. Calling rand before any call to srand generates the same sequence as calling srand with seed passed as 1.

  11. Sieht man mal davon ab das es AFAIK kein VC für Linux gibt kennt der Standard keine Datenbanken oder MySQL Server.

    Eventuell hilft veschieben in ein anderes Forum oder das forschen bei google news groups oder in einem für den MySQL Server eingerichtetes Forum. (Sry kenn mich mit dem Thema kaum aus). Dort dürfte man eher Leute finden die sich damit auskennen als im Standard C++

Fachinformatiker.de, 2024 by SE Internet Services

fidelogo_small.png

Schicke uns eine Nachricht!

Fachinformatiker.de ist die größte IT-Community
rund um Ausbildung, Job, Weiterbildung für IT-Fachkräfte.

Fachinformatiker.de App

Download on the App Store
Get it on Google Play

Kontakt

Hier werben?
Oder sende eine E-Mail an

Social media u. feeds

Jobboard für Fachinformatiker und IT-Fachkräfte

×
×
  • Neu erstellen...