Sortieren von bestimmten Inhalten aus Textdateien in C++

Kadamu

Grünschnabel
Hallo zusammen,

ich habe leider ein Problem beim Sortieren von bestimmten Inhalten aus Textdateien.
Ich hoffe ihr könnt mir dabei weiterhelfen.
Allgemein soll folgendes passieren: Ich lese mehrere Textdateien (aus einem bestimmten Verzeichnis) ein.
Jede einzelne Textdatei hat dabei jeweils einen bestimmten Inhalt, das so aussehen kann:

Textdatei Nr. 1 hat den Inhalt:
Aa1: Text...

Textdatei Nr. 2 hat den Inhalt:
Aa2: Text...

Textdatei Nr. 3 hat den Inhalt:
Bb1: Text...

...usw...

Wie ihr sicherlich schon bemerkt habt, sind die ersten zwei Buchstaben immer entweder Aa oder Bb und danach kommt eine Zahl. Die Zahl nach den zwei Buchstaben ist eine fortlaufende Zahl (und auch immer an der dritten Stelle), d. h. es könnte wie folgt aussehen: Aa1, Aa2,..,Aa10,..Aa100.
Der Inhalt aller eingehenden Textdateien soll nach dem Schema:
Aa1: Text...
Aa2: Text...
Aa10: Text...
Bb1: Text...
Bb2: Text...
.....usw...
sortiert werden und am Ende in einer neuen Textdatei gepeichert werden.

Mein eigentiches Problem ist dabei die Sortierung anhand der fortlaufenden Zahl.

Zur Veranschaulichung habe ich meine Funktion angehängt.
C++:
        // Globale Variablen:   
        std::string content = "";
        std::string contentAa = "";
        std::string contentBb = "";
        ...
        ...

        int searchAfterChar(std::string inputFile)
        {
            // "startsWith" is a function that returns all occurences of given characters in a text
            if (startsWith(inputFile, "Aa")){
                if (contentAa != ""){
                    found = contentAa.find(inputFile);
                    if (found = std::string::npos){
                        contentAa = contentAa + inputFile + "\n";
                    }
                    else{
                        cout << "Just tell me if I am here" << endl;
                    }
                }
                else{
                    contentAa = contentAa + inputFile + "\n";
                }
            }
            else if (startsWith(inputFile, "Bb")){
                if (contentBb != ""){
                    found = contentBb.find(inputFile);
                    if (found = std::string::npos){
                        contentBb = contentBb + inputFile + "\n";
                    }
                    else{
                        cout << "Just tell me if I am here" << endl;
                    }
                }
                else{
                    contentBb = contentBb + inputFile + "\n";
                }
            }
            content = contentAa + contentBb;

            return 0;
        }
        ...
        ...
Als Hinweis für euch; diese Funktion befindet sich in einer while-Schleife und wird so oft ausgeführt bis keine Textdateien im Verzeichnis vorhanden sind.
So würde ich zwar immer die richtige Reihenfolge hinsichtlich der Buchstaben, aber nicht hinsichtlich der fortlaufenden Zahl bekommen.
D.h. falls eine Textdatei mit dem Inhalt Aa3 vor einer Textdatei mit dem Inhalt Aa1 eingelesen wird, so hätte ich als Ergebnis die Reihenfolge Aa3, Aa1 anstatt richtigerweise Aa1, Aa3.

Hat jemand von euch eine Idee wie ich die Funktion so umbauen kann, dass ich am Ende die richtig sortierte Reihenfolge bekomme?

Danke & schöne Feiertage
Kadamu
 

sheel

I love Asm
Hi

ist nach der Zahl immer ein : ?
Muss das Sortieren selbst programmiert werden oder darf std::sort verwendet werden?
Kann man irgendeinen Maximalwert für die Zahlen annehmen?

Code:
found = contentAa.find(inputFile);
if (found = std::string::npos){
schaut zumindest falsch aus (= ist Zuweisung) ... aber mit std::sort ist die ganze derzeitige Funktion sowieso sinnlos.


Btw.,, als Hinweise:
Gibt es die Aa/Bb in anderen Groß/kleinschreibungsarten?
Kann man sich drauf verlassen, keine BOM zu finden?
Kann man sich drauf verlassen, dass die Dateien überhaupt vollständig in den RAM passen?
...
Je nach Antwort wären zusätzliche Massnahmen nötig.
 

Kadamu

Grünschnabel
Hi sheel,

Danke für die schnelle Rückmeldung!

Zu deinen Fragen:
Ja, nach der Zahl ist immer ein ":".

Wenn es mit std::sort möglich ist, darf das natürlich gerne verwendet werden.

Für die Zahlen ist zwar kein Maximalwert vorgesehen, dennoch wird es niemals über 100 hinaus gehen.

Die Funktion habe ich getestet und die hat meiner Meinung nach funktioniert (zumindest so, wie man es im Augenblick erwarten würde). Dennoch, die Funktion muss nicht so bleiben wie sie im Augenblick ist. Nach mehreren kläglichen Versuchen die Inhalte in einer sortierten Reihenfolge zu bringen, habe ich irgendwann diesen Stand belassen ;D

Nein, Aa/Bb bleibt in dieser Konstellation.

Die Dateien werden nicht sehr anspruchsvoll sein und daher in den RAM passen und es wird auch keine BOM zu finden sein.

EDIT: Ist im Code-Snippet nicht ersichtlich:
std::size_t found

Viele Grüße
Kadamu
 
Zuletzt bearbeitet:

sheel

I love Asm
Also, wenn man die Strings zB. alle in einem std::vector<std::string> vec hat (oder irgendwas anderes passendes laut Spec)...

Eine Vergleichsfunktion für zwei Strings, die true liefert, wenn String1 <= String2
C++:
bool stringCmp(const std::string &a, const std::string &b)
{
	//a and b both have the following format: begin is "Aa" or "Bb",
	//	followed by a number (fits into long), follwed by ":",
	//	followed by anything.
	//Aa is before Bb. If equal, smaller numbers are before larger numbers.
	//	Invalid strings go to the end.

	static constexpr char* begin1 = "Aa";
	static constexpr char* begin2 = "Bb";
	static constexpr std::size_t beginlen = 2; //begin1 and begin2: 2 bytes each

	if(a.find(begin1) == 0)
	{
		//a is Aa, b is not Aa, meaning a before b
		if(b.find(begin1) != 0) return true;
	}
	else if(a.find(begin2) == 0)
	{
		if(b.find(begin1) == 0) return false;
		if(b.find(begin2) != 0) return true;
	}
	else return false; // a is invalid

	if(!std::isdigit(a[beginlen])) return false; //a invalid
	if(!std::isdigit(b[beginlen])) return true;

	char *p;
	long numa = strtol(a.c_str(), &p, 10);
	if(p != ':') return false; //a invalid
	long numb = strtol(b.c_str(), &p, 10);
	if(p != ':') return true;

	return (numa <= numb);
}
Ungetestet.
Hab grad etwas wenig Zeit, genauere Erklärungen dazu gern später (oder wenn jemand anderes will, gern)

Mit der Funktion und dem Vector vec reicht dann ein einfaches
C++:
std::sort(vec.begin(), vec.end(), stringCmp);

std::size_t found
Was du mir damit sagen willst versteh ich leider nicht...