Stringvergleich - klein und Großbuchstaben
-
Hallo!
Ich stehe vor einem eigentlich simplen Problem:
Ich kann kein strcmp und jegliche andere Funktion, die dem ähnelt (dh habe praktisch nur die stdio (+Speicherverwaltung)Habe mal gesucht und bin auf die funktion von DirkB(besten Dank) von ein paar Threads weiter gekommen:
int mystrcmp(char a[], char b[]) { while( a[c] == b[c] ) { if( a[c] == '\0' ) return 0; c++; } return ( a[c] < b[c]) ? 1 : -1; }
Funktioniert für mich eigentlich einwandfrei bis auf eine Sache:
Hier können (natürlich) keine Groß/Kleinbuchstaben unterschieden werden.
Da ich weder toupper noch tolower benutzen dar, habe ich mir gedacht, dass ich wieder eine "manuelle" Funktion haben mss:char * mytolower(char *string) { int i; int len = strlen(string); /*Anmerkung: strlen wird ersetzt*/ for(i=0; i<len; i++) { if(string[i] >= 'A' && string[i] <= 'Z') { string[i] += 32; } } return string; }
Wenn ich jetzt in mystrcmp die Funktion hier einbaue:
mytolower(a);
Kommt direkt nach dem ausführen ein segmentation fault.
Also muss ich etwas übersehen, nur was?
-
Vermutlich machst du irgendwo eine Konvertierung von const char[] nach char[]. Dies wird zwar aus Kompatibilitätsgründen unterstützt, aber das Ergebnis, wenn man die chars tatsächlich verändert, ist dann eben meist ein Segfault.
Ich würde das nicht so aufziehen, wie du es machst. Eine Vergleichsfunktion sollte niemals die zu vergleichenden Variablen verändern! Also
1. Achte auf const-correctness. Schon DirkBs Funktion sollte eigentlich const char[] als Argumente nehmen.
2. Mach deine tolower-Funktion auf Bbuchstabenbasis, so wie die Standardfunktionen tolower/toupper
3. Vergleiche dann in deiner Zeichenkettenvergleichsfunktion die Ergebnisse deiner tolower-Funktion.
-
An dem Codeauschnitt liegt es nicht.
Wie ist denn a definiert und initialisiert?Etwa
char *a = "Hallo Welt!" mytolower(a);
?
Dann zeigt a auf ein Stringliteral. Die sind aber const, d.h. die dürfen nicht verändert werden.tolower bezieht sich eigentlich auch auf ein einzelnes Zeichen:
char mytolower(char b) { Hier der Vergleich return b; }
Und dann schreibst du ein anders mystrcmp das case insensitiv ist.
int mystrnocasecmp(char a[], char b[])}
while( tolower(a[c]) == tolower(b[c]))
....
// Eine Anpassung musst du noch machen
}
-
Du kannst den String vielleicht nicht ändern (und der Benutzer erwartet auch, dass du ihn nicht änderst), weil es z.B. ein String-Literal (also "blah") ist.
Mach lieber so was:
char mytolower(char in) { //... }
und vergleiche dann mytolower(str1[i]) und mytolower(str2[i]).
... zu langsam.
-
Ja danke! Es lag daran das es auf ein Stringliteral gezeigt hat. Habe es nun "kopiert" und die mit der kopierten arbeite ich weiter.
Jetzt nur noch eine letzte Kleinigkeit: Ich will das noch die Funktion mir die Umlaute ersetzt: (Bspw Ä->Ae oder aber auch Ä->a)
char * umlaute_konverter(char *string) { int i; int len = strlen(string); for(i=0; i<len; i++) { if(string[i] == 196) { string[i] = 65; } } return string; }
Hier will ich, dass er die 196 (Ä) durch 65 (A) ersetzt.
Aber so wie es dort steht funktioniert es nicht. mystrmcmp nimmt zumindest was anderes an. Also immer noch Ä.
-
Woher weisst du das Ä 196 ist?
-
Dachte durch den Dezimalwert der ASCII-Tabelle....
-
koschor schrieb:
Habe es nun "kopiert" und die mit der kopierten arbeite ich weiter.
Extrem ineffizient. Außerdem äußerst speicherintensiv. Warum machst du es nicht so, wie drei Leute dir unabhängig voneinander vorgeschlagen haben?
-
koschor schrieb:
Dachte durch den Dezimalwert der ASCII-Tabelle....
In einer ASCII Tabele steht das definitiv nicht drinnen. Die kennt nämlich nur die Codes von 0 bis 127.
mfg Martin
-
SeppJ schrieb:
koschor schrieb:
Habe es nun "kopiert" und die mit der kopierten arbeite ich weiter.
Extrem ineffizient. Außerdem äußerst speicherintensiv. Warum machst du es nicht so, wie drei Leute dir unabhängig voneinander vorgeschlagen haben?
Stimmt. Werde ich ändern.
mgaeckler schrieb:
In einer ASCII Tabele steht das definitiv nicht drinnen. Die kennt nämlich nur die Codes von 0 bis 127.
mfg Martin
Stimmt ebenso. Habe mich verlesen es war (natürlich) ISO-8859-1. Leider. Aber wie kann ich das realisieren? Ich meine "Zeichenweise" kann ich ja nicht vergleichen, weil ä ja mehr als ein Zeichen ist. Locale kann ich ebenso nicht "anfassen".
-
Die Konsole hat meist auch Codepage 850 und da liegen die Umlaute wieder woanders.
Lass es für den Anfang einfach sein, wenn dir so viele Hindernisse (kein tolower) in den Weg gelegt werden.
-
koschor schrieb:
Habe mich verlesen es war (natürlich) ISO-8859-1. Leider. Aber wie kann ich das realisieren? Ich meine "Zeichenweise" kann ich ja nicht vergleichen, weil ä ja mehr als ein Zeichen ist. Locale kann ich ebenso nicht "anfassen".
Da gibt leider der Standard nix her. Das ist Systemabhängig. Es hängt davon ab, mit welchem Zeichensatz die IDE, der Compiler und die Laufzeitumgebung arbeitet.
Wenn sie alle identisch sind, kannst Du auch einfach mit dem entsprechenden Zeichenliteral arbeiten. Ansonsten muß Du mit den Zeichencodes der Laufeitumgebung arbeiten. Hier mal ein kleines Beispiel:
#include <stdio.h> int main() { unsigned char c = 'Ä'; printf( "%u = %c\n", (unsigned int)c, c ); scanf( "%c", &c ); printf( "%u = %c\n", (unsigned int)c, c ); return 0; }
Wenn das in einer Windowskonsole ausgeführt wird und ich ein Ä eingebe, ergibt das folgende Ausgabe:
196 = - Ä 142 = Ä
Die Windowskonsole arbeitet nämlich mit einem anderen Zeichensatz wie die IDE (hier war das Borland C++).
Dein Beispiel hat aus zwei Gründen nicht funktioniert:
1. Dein char kann niemals den Wert 196 annehmen, weil es signed ist. Also einen Wertebereich von -128 bis + 127 hat. Du hättest also einen unsigned char nehmen oder mit -60 vergleichen müssen.
2. Die Windows Console (falls Du denn diese Benutzt hat) benutzt den Zeichensatz von DOS, da hat das Ä nicht den Wert 196 sondern 142.Edit: Die Umlaute sind übrigens auch im ISO-Zeichensatz nur ein Byte. Erst bei der UTF-8-kodierung sind es zwei.
mfg Martin
-
Nutze gcc unter Debian.
Mittels "locale" kann man ja sehen welches Charset verwendet wird. Bei mir ist es UTF-8 (zumindest in der Konsole). Deswegen kommt auch die Warnung:Zeichenkonstante mit mehreren Zeichen [-Wmultichar]
Was jetzt natürlich verständlich ist, wenn ich
string[i]=='Ä'
abfragen würde. (Wenn man trotz Warnung weitermacht klappt es nicht.)
Letztlich komme ich zu dem Schluss, dass es nicht "die" Lösung für das Problem gibt, ohne locale zu verwenden oder wide-chars.
die Funktion strcmp kann ich auch nicht entsprechend verändern, sodass es auch umlaute vergleichen kann, oder?.
-
koschor schrieb:
Letztlich komme ich zu dem Schluss, dass es nicht "die" Lösung für das Problem gibt, ohne locale zu verwenden oder wide-chars.
Blitzmerker!
koschor schrieb:
die Funktion strcmp kann ich auch nicht entsprechend verändern, sodass es auch umlaute vergleichen kann, oder?.
Dafür gibt es strcoll.