Benutzer:Stefan Knauf/Babellistenprogramm.cpp

aus Wikipedia, der freien Enzyklopädie
Zur Navigation springen Zur Suche springen


C++-Programm, mit dem man prüfen kann, ob die in der Kategorie Benutzer nach Sprache auftauchenden Sprachen auch alle auf den Projektseiten Wikipedia:Babel oder Wikipedia:Babel/Dialekt aufgelistet sind. Das Programm gibt eine Liste der Sprachkürzel aus, die nur in der Kategorie auftauchen. Näheres zur Handhabung steht im Quelltextkommentar über dem eigentlichen Programmcode.
Leider habe ich nicht herausgefunden, wie man in C++ mit UTF-8-kodierten Dateien umgeht (einfach die Typen char und string durch wchar_t und wstring zu ersetzen, funktioniert nicht, weil die Operationen zum Arbeiten mit Dateien stets jedes Byte als ein Zeichen interpretieren), was bei Nicht-ASCII-Zeichen (z.B. Umlauten) prinzipiell zu Problemen führen kann; aber bei mir funktioniert das Programm auch so einwandfrei.




// C++

// 14.1.2013, Stefan Knauf

/*

Mit diesem Programm lassen sich die Einträge der Kategorie
"Benutzer nach Sprache" (https://de.wikipedia.org/wiki/Kategorie:Benutzer:nach_Sprache)
mit den Einträgen auf den Babel-Projektseiten "Wikipedia:Babel" und
"Wikipedia:Babel/Dialekt" abgleichen. Das Programm benötigt beim Aufruf als
Parameter zwei Textdateien, in der ersten muss der HTML-Quelltext der Kategorie
und in der zweiten der Wiki-Quelltext der Projektseiten stehen. Ein korrekter
Programmaufruf sieht also beispielsweise so aus:

Babellistenprogramm Kategorie.txt Projektseiten.txt

Die Dateinamen dürfen natürlich keine Leerzeichen enthalten.

Weil die Kategorie momentan zwischen 200 und 400 Einträge hat, wird sie derzeit
auf zwei Seiten verteilt dargestellt. Das Programm benötigt eine Datei, in der
der HTML-Quelltext beider Seiten steht. Desweiteren benötigt das Programm eine
Datei, in der der Wiki-Quelltext beider Projektseiten "Wikipedia:Babel" und
"Wikipedia:Babel/Dialekt" steht.

Im HTML-Quelltext der Kategorie liest das Programm die Sprachkürzel aus den
Links auf die Unterkategorien aus, wo die Umlaute (von manchen der
Dialektkürzel, z.B. kö für Kölsch oder frä für Fränkisch) natürlich in
UTF-8-%-URL-Kodierung angegeben sind. Genauer sucht das Programm nach
"wiki/Kategorie:User_" und interpretiert alles dahinter bis zum nächsten
Gänsefüßchen (") als Sprachkürzel.

Im Wiki-Quelltext der Projektseiten sucht das Programm im Prinzip nach dem
Parameter der Sprachkürzel in der Auflistung der ganzen Sprachen, also im
Prinzip nach "Kürzel=[Sprachkürzel]". Leerzeichen vor und hinter dem
Gleichheitszeichen werden vom Programm ignoriert. Für das Programm beginnt das
Sprachkürzel hinter dem Gleichheitszeichen (bzw. nach dem letzten Leerzeichen
dahinter) und endet vor dem nächsten "|", Leerzeichen oder Zeilenende. Umlaute
im Sprachkürzel werden vom Programm in die UTF-8-%-URL-Kodierung überführt.

Hinweis zur Kodierung: Der als Muster verwendete Parameter "Kürzel" von der
auf den Projektseiten verwendeten Vorlage "Babel-Sprachverzeichnis" und einige
der Sprachkürzel enthalten Umlaute. Deswegen enthält der Quelltext dieses
Programms natürlich auch welche. Deswegen ist das Programm an der Stelle, wo der
Wiki-Quelltext der Projektseiten eingelesen wird, prinzipiell anfällig für
Kodierungsprobleme. Wenn man es unter Windows 7 mit Dev-C++ 4.9.9.8 kompiliert
und die Textdatei mit dem Wiki-Quelltext der Projektseiten als "ANSI" kodiert,
funktioniert das Programm jedenfalls einwandfrei. (Ich vermute, mein
Betriebssystem meint Windows-1252, wenn es "ANSI" sagt.)
Die Kodierung der Datei mit dem HTML-Quelltext der Kategorie ist unkritisch,
weil für das Programm hier ausschließlich ASCII-Zeichen wichtig sind.


*/
using namespace std;

#include<vector> //enthält die praktische Vektor-Klasse vector<irgendein Typ>
#include<iostream> //enthält die Befehle zum Schreiben auf den Bildschirm
#include<fstream> //enthält die Befehle zum Schreiben in und zum Lesen aus Dateien
#include<string> //enthält den Kram zu Strings, also zu Zeichenketten



struct Babellisteneintrag //Typdefinition für ein Tripel aus Sprachcode (string) und zwei Booleschen Variablen dafür,
//ob die Sprache in der Kategorie oder den Projektseiten aufgelistet ist
 {string Sprachkuerzel;
  bool Kategorie;
  bool Projektseite;
 };
 

string Prozentkodierer (string Wort) //ersetzt die Umlaute ä, ö und ü und das ß in einem String durch die UTF-8-%-URL-Kodierung
 {string Ausgabe="";
  for (int i=0; i<Wort.size(); i++)
   {switch(Wort[i])
	 {case 'ä' : Ausgabe=Ausgabe+"%C3%A4"; break;
	  case 'Ä' : Ausgabe=Ausgabe+"%C3%84"; break;
	  case 'ö' : Ausgabe=Ausgabe+"%C3%B6"; break;
	  case 'Ö' : Ausgabe=Ausgabe+"%C3%96"; break;
	  case 'ü' : Ausgabe=Ausgabe+"%C3%BC"; break;
	  case 'Ü' : Ausgabe=Ausgabe+"%C3%9C"; break;
	  case 'ß' : Ausgabe=Ausgabe+"%C3%9F"; break;
	  default  : Ausgabe.push_back(Wort[i]);
	 }
   }
  return Ausgabe;
 }


vector<Babellisteneintrag> FuelleKategorieein (vector<Babellisteneintrag> Babelliste, string Dateiname)
//liest die Sprachkürzel aus dem HTML-Quelltext einer Kategorieseite aus.
//Es durchsucht den Quelltext nach "wiki/Kategorie:User_" und interpretiert alles dahinter bis
//zum nächsten Gänsefüßchen (") als Sprachkürzel, d.h. die Kürzel werden aus den URL der Links
//auf die Unterkategorien ausgelesen. Umlaute stehen dabei natürlich in UTF-8-%-URL-Kodierung.
 {ifstream Datei;
  char x;
  Datei.open(Dateiname.c_str());
  while (Datei.good())
   {Datei.get(x);
    if (x=='w' && Datei.good())
     {Datei.get(x);
      if (x=='i' && Datei.good())
       {Datei.get(x);
        if (x=='k' && Datei.good())
         {Datei.get(x);
          if (x=='i' && Datei.good())
           {Datei.get(x);
            if (x=='/' && Datei.good())
             {Datei.get(x);
              if (x=='K' && Datei.good())
               {Datei.get(x);
                if (x=='a' && Datei.good())
                 {Datei.get(x);
                  if (x=='t' && Datei.good())
                   {Datei.get(x);
                    if (x=='e' && Datei.good())
                     {Datei.get(x);
                      if (x=='g' && Datei.good())
                       {Datei.get(x);
                        if (x=='o' && Datei.good())
                         {Datei.get(x);
                          if (x=='r' && Datei.good())
                           {Datei.get(x);
                            if (x=='i' && Datei.good())
                             {Datei.get(x);
                              if (x=='e' && Datei.good())
                               {Datei.get(x);
                                if (x==':' && Datei.good())
                                 {Datei.get(x);
                                  if (x=='U' && Datei.good())
                                   {Datei.get(x);
                                    if (x=='s' && Datei.good())
                                     {Datei.get(x);
                                      if (x=='e' && Datei.good())
                                       {Datei.get(x);
                                        if (x=='r' && Datei.good())
                                         {Datei.get(x);
                                          if (x=='_' && Datei.good())
                                           {string Sprachkuerzel="";
                                            Datei.get(x);
                                            while (x!='"' && Datei.good()) //liest das Sprachkürzel ein
                                             {Sprachkuerzel.push_back(x);
                                              Datei.get(x);
                                             }
                                            int i=0;
                                            bool fertig=false;
                                            while (i<Babelliste.size() && !fertig) //wenn das Kürzel bereits in der Babelliste stand, wird hier vermerkt, dass es auch in der Kategorie war
                                             {if (Sprachkuerzel==Babelliste[i].Sprachkuerzel)
     	                                       {Babelliste[i].Kategorie=true;
                                                fertig=true;
                                               }
                                              else
                                               {i++;
                                               }
                                             }
                                            if (!fertig) //wenn das Kürzel nicht in der Babelliste stand, wird es hier eingeräumt
                                             {Babellisteneintrag Eintrag;
    	                                      Eintrag.Sprachkuerzel=Sprachkuerzel;
                                              Eintrag.Kategorie=true;
                                              Eintrag.Projektseite=false;
                                              Babelliste.push_back(Eintrag);
                                             }
                                           }
                                         }
                                       }
                                     }
                                   }
                                 }
                               }
                             }
                           }
                         }
                       }
                     }
                   }
                 }
               }
             }
           }
         }
       }
     }
   }
  Datei.close();
  return Babelliste;
 }
 
vector<Babellisteneintrag> FuelleProjektseitenein (vector<Babellisteneintrag> Babelliste, string Dateiname)
//liest aus dem Wikiquelltext der Babel-Projektseiten die Sprachkürzel der dort aufgelisteten
//Sprachen aus. Es Durchsucht den Quelltext nach dem Muster
//"Kürzel[vielleicht Leerzeichen]=[vielleicht Leerzeichen][Sprachkürzel]";
//ersetzt Umlaute in den Sprachkürzeln durch die UTF-8-%-URL-Kodierung;
 {char x;
  ifstream Datei;
  Datei.open(Dateiname.c_str());
  while(Datei.good())
   {Datei.get(x);
    if (x=='K' && Datei.good())
     {Datei.get(x);
      if (x=='ü' && Datei.good())
       {Datei.get(x);
        if (x=='r' && Datei.good())
         {Datei.get(x);
          if (x=='z' && Datei.good())
           {Datei.get(x);
            if (x=='e' && Datei.good())
             {Datei.get(x);
              if (x=='l' && Datei.good())
               {Datei.get(x);
                while (x==' ' && Datei.good()) //überspringt zwischen dem Parameternamen "Kürzel" und dem folgenden Gleichheitszeichen eventuell vorhandene Leerzeichen
                 {Datei.get(x);
                 }
                if (x=='=' && Datei.good())
                 {Datei.get(x);
                  while (x==' ' && Datei.good()) //überspringt zwischen dem Gleichheitszeichen und dem Sprachkürzel eventuell vorhandene Leerzeichen
                   {Datei.get(x);
                   }
                  string Sprachkuerzel="";
                  while (x!=' ' && x!='|' && x!='\n' && x!='\r' && Datei.good()) //liest das Sprachkürzel ein
                   {Sprachkuerzel.push_back(x);
                    Datei.get(x);
                   }
                  Sprachkuerzel=Prozentkodierer(Sprachkuerzel); //ersetzt die Umlaute im Sprachkürzel durch die UTF-8-%-URL-Kodierung
                  int i=0;
                  bool fertig=false;
                  while (i<Babelliste.size() && !fertig) //wenn das Kürzel bereits in der Babelliste auftaucht, wird hier vermerkt, dass es auch auf einer der Projektseiten stand
                   {if (Sprachkuerzel==Babelliste[i].Sprachkuerzel)
                     {Babelliste[i].Projektseite=true;
                      fertig=true;
                     }
                    else
                     {i++;
                     }
                   }
                  if (!fertig) //wenn das Kürzel nicht schon in der Babelliste stand, wird es hier eingeräumt
                   {Babellisteneintrag Eintrag;
                    Eintrag.Sprachkuerzel=Sprachkuerzel;
                    Eintrag.Kategorie=false;
                    Eintrag.Projektseite=true;
                    Babelliste.push_back(Eintrag);
                   }
                 }
               }
             }
           }
         }
       }
     }
   }
  Datei.close();
  return Babelliste;
 }


void Listenausgabe (vector<Babellisteneintrag> Babelliste) //gibt alle Sprachkürzel einer Babelliste aus; wurde nur zu Testzwecken verwendet und ist fürs fertige Programm völlig überflüssig
 {for (int i=0; i<Babelliste.size(); i++)
   {cout << Babelliste[i].Sprachkuerzel << endl;
   }
 }

void nurKat (vector<Babellisteneintrag> Babelliste) //gibt alle Sprachkürzel aus, die nur in der Kategorie auftauchten
 {for (int i=0; i<Babelliste.size(); i++)
   {if (Babelliste[i].Projektseite==false)
     {cout << Babelliste[i].Sprachkuerzel << endl;
     }
   }
 }

int main(int argc, char ** argv)
 {if (argc<3) //Die Bedingung ist erfüllt, wenn dem Programm zu wenig Parameter übergeben wurden.
   {cout << "Dieses Programm benötigt als Parameter zwei Textdateien, in der ersten den HTML-Quelltext der Benutzer-nach-Sprache-Kategorie und in der zweiten den Wiki-Quelltext der Babel-Projektseiten. Näheres steht in der Quelltextdatei ganz oben." << endl;
   }
  else
   {string Kategorie=argv[1];
    string Projektseiten=argv[2];
    vector<Babellisteneintrag> Babelliste(0);
    Babelliste = FuelleKategorieein(FuelleProjektseitenein(Babelliste, Projektseiten), Kategorie);
    cout << "Folgende Sprachkürzel tauchten nur in der Kategorie auf: " << endl;
    nurKat(Babelliste);
    cout << "Insgesamt wurden " << Babelliste.size() << " verschiedene Sprachkürzel in Kategorie und Projektseiten gefunden." << endl;
   }
  return 0;
 }