C: Transkriptionsprogramm mit wchar_t

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
paedubucher
Beiträge: 938
Registriert: 22.02.2009 16:19:02
Lizenz eigener Beiträge: GNU Free Documentation License
Wohnort: Schweiz
Kontaktdaten:

C: Transkriptionsprogramm mit wchar_t

Beitrag von paedubucher » 15.10.2011 12:03:42

Hallo allerseits

Für mein Studium (Slavistik) muss ich oftmals kyrillischen (genauer: russischen) Text transkribieren. Und da denkt sich doch der frühere Informatiker, hier würde sich doch ein kleines C-Programm wunderbar ausnehmen! Als ersten Schritt möchte ich das ganze russische Alphabet in einem Array darstellen, und zwar immer zuerst Grossbuchstabe, dann Kleinbuchstabe, also: АаБбВвГгДд usw. Dies erledigt die Funktion get_cyrillic() für mich (siehe NoPaste-Eintrag35977).

Nun mein Problem: Die obere Schleife, die den Rückgabewert der Funktion get_cyrillic verwendet, funktioniert nicht. Sie gibt zunächst 'A' aus, dann auf der nächsten Zeile ein paar Fragezeichen, bricht danach aber ab. Die untere Schleife innerhalb der Funktion get_cyrillic, die ich nur zu Debugging-Zwecken dort eingefügt habe, funktioniert jedoch tadellos und gibt von Аа bis Яя alles fehlerfrei aus.

Mein bisheriger Verdacht war, dass das in der oberen Schleife nicht korrekt auf das nächste Array-Element weiterspringt. Dann habe ich es mit folgendem Code probiert:

Code: Alles auswählen

c += sizeof(wchar_t)
Dieser produziert jedoch die gleiche Ausgabe.

Als Compiler verwende ich tcc. Verwende ich gcc, komme ich immerhin bis zu АаБбВв. Dazu wird noch die Warnung ausgegeben, dass ich die Adresse einer lokalen Variable zurückgebe. Als Erklärung für meinen Dilettantismus darf ich beifügen, dass ich jahrelang als Java-Programmierer herumgehurt habe und nun von dieser Programmiersprache mit ihren Ansätzen (Factory-Methoden und solcherlei) völlig durchtrieben bin.

Danke und Gruss,
paedubucher
Zuletzt geändert von paedubucher am 19.10.2011 13:51:43, insgesamt 3-mal geändert.
Habe nun, ach! Java
Python und C-Sharp,
Und leider auch Visual Basic!
Durchaus programmiert mit heissem Bemühn.
Da steh' ich nun, ich armer Tor!
Und bin so klug als wie zuvor.

owl102

Re: C: wchar_t Array zurückgeben

Beitrag von owl102 » 15.10.2011 14:23:33

paedubucher hat geschrieben:Dazu wird noch die Warnung ausgegeben, dass ich die Adresse einer lokalen Variable zurückgebe.
Diese Warnung ist richtig, da cyrillic[] auf dem Stack angelegt wird, und dessen Inhalt nach dem Ende der Funktion get_cyrillic() gar nicht mehr verfügbar ist. (Für Java-Programmierer sicherlich ungewohnt, da dort Arrays und Objekte grundsätzlich auf dem Heap angelegt werden. Wollte man das Array in C++ auf dem Heap anlegen, müsste man dies explizit über "wchar_t *cyrillic = new wchar_t[ALPH_LEN * 2 + 1]" machen.)

Abhilfen: Entweder "static wchar_t cyrillic[ALPH_LEN * 2 + 1]" schreiben (also mit "static" am Anfang), oder aber cyrillic[] global anlegen. (Oder eben auf dem Heap mit new anlegen, siehe oben.)

paedubucher
Beiträge: 938
Registriert: 22.02.2009 16:19:02
Lizenz eigener Beiträge: GNU Free Documentation License
Wohnort: Schweiz
Kontaktdaten:

Re: C: wchar_t Array zurückgeben

Beitrag von paedubucher » 15.10.2011 15:57:22

owl102 hat geschrieben:
paedubucher hat geschrieben:Dazu wird noch die Warnung ausgegeben, dass ich die Adresse einer lokalen Variable zurückgebe.
Diese Warnung ist richtig, da cyrillic[] auf dem Stack angelegt wird, und dessen Inhalt nach dem Ende der Funktion get_cyrillic() gar nicht mehr verfügbar ist. (Für Java-Programmierer sicherlich ungewohnt, da dort Arrays und Objekte grundsätzlich auf dem Heap angelegt werden. Wollte man das Array in C++ auf dem Heap anlegen, müsste man dies explizit über "wchar_t *cyrillic = new wchar_t[ALPH_LEN * 2 + 1]" machen.)

Abhilfen: Entweder "static wchar_t cyrillic[ALPH_LEN * 2 + 1]" schreiben (also mit "static" am Anfang), oder aber cyrillic[] global anlegen. (Oder eben auf dem Heap mit new anlegen, siehe oben.)
Wäre das C-pendant zu "new", um ein "Objekt" auf dem Heap anzulegen, etwa malloc? Eigentlich könnte ich das Array auch in main anlegen und es als Parameter übergeben. Die Funktion befüllt das Array dann mit Werten, hat dann aber keinen Rückgabewert mehr (void). Ich habe früher mal gehört, dass in Garbage-Collection-losen Programmiersprachen jede Funktion die Datenobjekte wieder entsorgen soll, die sie hergestellt hat...

Nachtrag: Ich habe es jetzt folgendermassen gelöst:

Code: Alles auswählen

#include <stdio.h>
#include <wchar.h>
#include <locale.h>

#define ALPH_LEN 32

void get_cyrillic(wchar_t *); 

int main(int argc, char *argv[])
{
    wchar_t cyrillic[ALPH_LEN * 2 + 1];
    get_cyrillic(cyrillic);
    wchar_t *c;
    setlocale(LC_ALL, "");
    for (c = cyrillic; *c != '\0'; c++) 
        wprintf(L"%lc\n", *c);
    return 0;
}

void get_cyrillic(wchar_t *cyrillic)
{
    wchar_t upper, lower;
    int n = 0;

    for (upper = 0x0410, lower = 0x430;
        upper <= 0x042f && lower <= 0x044f;
        upper++, lower++) {
        cyrillic[n++] = upper;
        cyrillic[n++] = lower;
    }
    cyrillic[n] = '\0';
    wchar_t *c;
}
So, nun kann ich weiterprogrammieren. Vielleicht melde ich mich dann noch einmal mit Fragen zu unions. Schliesslich kann es bei der nicht-wissenschaftlichen Transkription (zu deutsch) vorkommen, dass ein Zeichen in mehrere andere Zeichen transkribiert werden muss. Aber zuerst einmal die einfache wissenschaftliche Transkription...
Habe nun, ach! Java
Python und C-Sharp,
Und leider auch Visual Basic!
Durchaus programmiert mit heissem Bemühn.
Da steh' ich nun, ich armer Tor!
Und bin so klug als wie zuvor.

owl102

Re: C: wchar_t Array zurückgeben

Beitrag von owl102 » 15.10.2011 16:05:03

paedubucher hat geschrieben:Wäre das C-pendant zu "new", um ein "Objekt" auf dem Heap anzulegen, etwa malloc?
Ja, malloc() oder calloc().
Ich habe früher mal gehört, dass in Garbage-Collection-losen Programmiersprachen jede Funktion die Datenobjekte wieder entsorgen soll, die sie hergestellt hat...
Stimmt, aber nur, wenn sie das Datenobjekt nicht als Rückgabewert liefert, in eine Tabelle einträgt (wo es dann ggf. von einer anderen Funktion ausgetragen und entsorgt wird), usw. Sprich: Wenn das Datenobjekt nicht mehr in Gebrauch ist, dann gibt man es frei, ansonsten (logischerweise) nicht.

Hört sich einfach an, es ist für Java-Programmierer aber sicherlich ungewohnt, daran denken zu müssen. Dafür ist es für mich in Java extrem ungewohnt, meinen Kram nicht einfach in Destruktoren wegräumen zu können, sondern stattdessen alles außer Speicher (Dateien, Sockets, ...) immer selber schließen zu müssen.

Nachtrag: Zu unions hat AFAIK Bjarne Stroustrup mal sinngemäß geschreiben, daß er sie in C++ am liebsten rausgeschmissen hätte, sie aber wegen der angestrebten Abwärtskompatibilität zu C zähneknirschend dringelassen hat.

paedubucher
Beiträge: 938
Registriert: 22.02.2009 16:19:02
Lizenz eigener Beiträge: GNU Free Documentation License
Wohnort: Schweiz
Kontaktdaten:

Re: C: wchar_t Array zurückgeben

Beitrag von paedubucher » 15.10.2011 22:29:53

owl102 hat geschrieben:Nachtrag: Zu unions hat AFAIK Bjarne Stroustrup mal sinngemäß geschreiben, daß er sie in C++ am liebsten rausgeschmissen hätte, sie aber wegen der angestrebten Abwärtskompatibilität zu C zähneknirschend dringelassen hat.
Soweit ich das verstanden habe bringen mir unions hier gar nichts. Es wird ja eh so viel Speicher reserviert, wie das grösste Objekt der union einnimmt. Ich habe nun einen anderen Ansatz gewählt (wchar_t char-arrays) und bin damit auch wieder im Begriff zu scheitern:

Code: Alles auswählen

    wchar_t scientific[][] = {
        L"A", L"a",
        L"B", L"b",
        L"V", L"v",
        L"G", L"g",
        L"D", L"d",
        L"E", L"e",
        {0x00cb, L'\0'}, {0x00eb, L'\0'},
        {0x017d, L'\0'}, {0x017e, L'\0'}
    };
    int n;
    for (n = 0; n < 16; n++) {
        wprintf(L"%ls\n", scientific[n]);
    }
Die Zeichen, die ich als wchar_t-Arrays angebe (13, 14, 15 und 16: die vier letzten im Array), werden nur als '?' auf der Konsole ausgegeben. Eigentlich sollten doch die als Strings verstanden werden, oder? Mit wchar_t habe ich den Dreh definitiv noch nicht raus.

Übrigens: Kann mir jemand gutes C-Ausbildungsmaterial empfehlen? Das K&R-Buch habe ich vor ein paar Jahren mal durchgearbeitet. Natürlich ist das Werk gut, ein bisschen angestaubt wirkt es aber doch, zumal solche Sachen wie Unicode darin nicht besprochen werden...
Habe nun, ach! Java
Python und C-Sharp,
Und leider auch Visual Basic!
Durchaus programmiert mit heissem Bemühn.
Da steh' ich nun, ich armer Tor!
Und bin so klug als wie zuvor.

owl102

Re: C: wchar_t Array zurückgeben

Beitrag von owl102 » 16.10.2011 09:49:02

paedubucher hat geschrieben:wchar_t scientific[][] = {
Und das bekommst du übersetzt? Ich nicht: "test.c:3:13: Fehler: Feldtyp hat unvollständigen Elementtypen"

Ich hätte das so geschrieben:

Code: Alles auswählen

    const wchar_t *scientific[] = {
        L"A", L"a",
        L"B", L"b",
        L"V", L"v",
        L"G", L"g",
        L"D", L"d",
        L"E", L"e",
        L"\x0cb", L"\x0eb",
        L"\x17d", L"\x17e"
    };
Bei den letzten vier erhalte ich allerdings auch nur "?" als Ausgabe.
Mit wchar_t habe ich den Dreh definitiv noch nicht raus.
Ich habe auch keine Ahnung von UCS-2, sorry, verwende immer UTF-8-Kodierung, da ich GTK+ Anwendungen schreibe.
Übrigens: Kann mir jemand gutes C-Ausbildungsmaterial empfehlen? Das K&R-Buch habe ich vor ein paar Jahren mal durchgearbeitet.
Auch hier muß ich passen, außer dem K&R habe ich nie ein anderes C-Buch gelesen.

paedubucher
Beiträge: 938
Registriert: 22.02.2009 16:19:02
Lizenz eigener Beiträge: GNU Free Documentation License
Wohnort: Schweiz
Kontaktdaten:

Re: C: wchar_t Array zurückgeben

Beitrag von paedubucher » 16.10.2011 13:28:12

owl102 hat geschrieben: Ich hätte das so geschrieben:

Code: Alles auswählen

    const wchar_t *scientific[] = {
        L"A", L"a",
        L"B", L"b",
        L"V", L"v",
        L"G", L"g",
        L"D", L"d",
        L"E", L"e",
        L"\x0cb", L"\x0eb",
        L"\x17d", L"\x17e"
    };
Bei den letzten vier erhalte ich allerdings auch nur "?" als Ausgabe.
Bei mir genau das Gleiche... Komisch, das sollte doch irgendwie zu schaffen sein...
Habe nun, ach! Java
Python und C-Sharp,
Und leider auch Visual Basic!
Durchaus programmiert mit heissem Bemühn.
Da steh' ich nun, ich armer Tor!
Und bin so klug als wie zuvor.

paedubucher
Beiträge: 938
Registriert: 22.02.2009 16:19:02
Lizenz eigener Beiträge: GNU Free Documentation License
Wohnort: Schweiz
Kontaktdaten:

Re: C: Transkriptionsprogramm mit wchar_t

Beitrag von paedubucher » 17.10.2011 16:52:36

Ups, sorry. Mein obiger Code funktioniert eigentlich perfekt. Das Problem ist, dass ich ganz oben (zu Testwecken) "setlocal()" auskommentiert habe. Darum erschienen in der Ausgabe immer Fragezeichen. So lernt man's :wink:
Habe nun, ach! Java
Python und C-Sharp,
Und leider auch Visual Basic!
Durchaus programmiert mit heissem Bemühn.
Da steh' ich nun, ich armer Tor!
Und bin so klug als wie zuvor.

paedubucher
Beiträge: 938
Registriert: 22.02.2009 16:19:02
Lizenz eigener Beiträge: GNU Free Documentation License
Wohnort: Schweiz
Kontaktdaten:

Re: C: Transkriptionsprogramm mit wchar_t

Beitrag von paedubucher » 17.10.2011 22:58:56

Wunderbar, jetzt läuft das Ding. Hier noch der vollständige Sourcecode: NoPaste-Eintrag35988 (das eigentliche Programm) und NoPaste-Eintrag35989 (wissenschaftliche Transkription).

Jetzt sollte ich das ganze noch auf meine Website bringen, am besten gleich mit Textfeld. Vielleicht stelle ich diese Woche noch ein paar Fragen zu Python und CGI :wink:
Habe nun, ach! Java
Python und C-Sharp,
Und leider auch Visual Basic!
Durchaus programmiert mit heissem Bemühn.
Da steh' ich nun, ich armer Tor!
Und bin so klug als wie zuvor.

Benutzeravatar
Meillo
Moderator
Beiträge: 9241
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: C: Transkriptionsprogramm mit wchar_t

Beitrag von Meillo » 18.10.2011 09:01:32

btw:
paedubucher hat geschrieben:Wunderbar, jetzt läuft das Ding. Hier noch der vollständige Sourcecode: NoPaste-Eintrag35988 (das eigentliche Programm) und NoPaste-Eintrag35989 (wissenschaftliche Transkription).
Schoen, wenn Themen auf so vorbildliche Art abgeschlossen werden. :THX:
Use ed once in a while!

paedubucher
Beiträge: 938
Registriert: 22.02.2009 16:19:02
Lizenz eigener Beiträge: GNU Free Documentation License
Wohnort: Schweiz
Kontaktdaten:

Re: C: Transkriptionsprogramm mit wchar_t

Beitrag von paedubucher » 19.10.2011 13:29:53

Meillo hat geschrieben:btw:
paedubucher hat geschrieben:Wunderbar, jetzt läuft das Ding. Hier noch der vollständige Sourcecode: NoPaste-Eintrag35988 (das eigentliche Programm) und NoPaste-Eintrag35989 (wissenschaftliche Transkription).
Schoen, wenn Themen auf so vorbildliche Art abgeschlossen werden. :THX:
Apropos abschliessen: Wenn gerade ein Kenner der Unix-Philosophie zugegen ist, hätte ich noch eine Frage. Ich möchte das Programm etwas flexibler machen, sodass man es folgendermassen aufrufen kann:

1. Direkt mit kyrillsichem Text:

Code: Alles auswählen

transkript Лев Николaевич Толстoй
Hier sollen einfach alle Parameter 1:1 transkribiert werden.

2. Als Datei:

Code: Alles auswählen

transkript vojna-i-mir.txt
Hier soll die Datei im Parameter transkribiert und ausgegeben werden. (Oder auch mehrere Dateien: transkript vojna-i-mir.txt prestuplene-i-nakazane.txt)

Möglich könnte es dann auch sein, dass die Parameter durchmischt sind, also Dateinamen und kyrillischer Text:

Code: Alles auswählen

transkript Лев Николaевич Толстoй vojna-i-mir.txt
Wie gehe ich jetzt am besten vor? Soll ich einfach alle Parameter durchgehen und schauen, welchen ich als Datei öffnen kann? Also:

Code: Alles auswählen

if((foo = fopen(argv[n] /* andere Parameter /*) != NULL)
    transkribiere(foo);
else
    transkribiere(argv[n]);
Oder sollte man generell Dateien nur über stdio einlesen?

Code: Alles auswählen

cat vojna-i-mir.txt prestuplene-i-nakazane.txt | transkript
Leider habe ich das kleine Büchlein von Mike Gancarz nur zu Hause liegen und nicht hier an der Uni dabei...
Habe nun, ach! Java
Python und C-Sharp,
Und leider auch Visual Basic!
Durchaus programmiert mit heissem Bemühn.
Da steh' ich nun, ich armer Tor!
Und bin so klug als wie zuvor.

Benutzeravatar
Meillo
Moderator
Beiträge: 9241
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: C: Transkriptionsprogramm mit wchar_t

Beitrag von Meillo » 19.10.2011 13:51:47

paedubucher hat geschrieben: Wenn gerade ein Kenner der Unix-Philosophie zugegen ist, hätte ich noch eine Frage.
Ha! Sowas hab ich ja noch nicht gehoert. ;-)

Ich möchte das Programm flexibler machen, sodass man es folgendermassen aufrufen kann:

1. Direkt mit kyrillsichem Text:

Code: Alles auswählen

transkript Лев Николaевич Толстoй
Hier sollen einfach alle Parameter 1:1 transkribiert werden.
Da wird dir dein Terminal oder deine Shell vielleicht einen Strich durch die Rechnung machen, wenn die nicht vollstaendigen UTF-8-Support bieten. Aber das ist nur geraten.
2. Als Datei:

Code: Alles auswählen

transkript vojna-i-mir.txt
Hier soll die Datei im Parameter transkribiert und ausgegeben werden. (Oder auch mehrere Dateien: transkript vojna-i-mir.txt prestuplene-i-nakazane.txt)
Das ist der normale Fall.
Möglich könnte es dann auch sein, dass die Parameter durchmischt sind, also Dateinamen und kyrillischer Text:

Code: Alles auswählen

transkript Лев Николaевич Толстoй vojna-i-mir.txt
Wie soll das Programm unterscheiden koennen welches Argument was ist? Im allgemeinen Fall ist das unmoeglich, deshalb wird so eine Aufrufvariante von den gaengigen Tools auch nicht unterstuetzt.
Wie gehe ich jetzt am besten vor?
Wenn Parameter da sind, dann sind das Dateien. Wenn keine Parameter da sind, dann lese von stdin (da kannst du dann deine Worte direkt hintippen). Optional kannst du das Argument `-' unterstuetzen, bei dem du dann keine benannte Datei oeffnest sondern von stdin liest.

Schau dir wc(1), cat(1), spell(1) an, die machen das alle so.
Soll ich einfach alle Parameter durchgehen und schauen, welchen ich als Datei öffnen kann?
Nein.

Oder sollte man generell Dateien nur über stdio einlesen?

Code: Alles auswählen

cat vojna-i-mir.txt prestuplene-i-nakazane.txt | transkript
Nicht nur, aber auch.

Leider habe ich das kleine Büchlein von Mike Gancarz nur zu Hause liegen und nicht hier an der Uni dabei...
In diesem Fall wird dir die Manpage von wc(1) auch weiterhelfen. :-)
Use ed once in a while!

paedubucher
Beiträge: 938
Registriert: 22.02.2009 16:19:02
Lizenz eigener Beiträge: GNU Free Documentation License
Wohnort: Schweiz
Kontaktdaten:

Re: C: Transkriptionsprogramm mit wchar_t

Beitrag von paedubucher » 02.11.2011 13:37:35

Hallo Meillo

Besten Dank für deine Antwort. Da ich gerade andersweitig beschäftigt war, konnte ich bisher noch nicht antworten (und auch mein kleines Programm noch nicht fertig implementieren).

Ich werde es nun so machen, dass das Programm von stdin liest, falls kein Dateiparameter angegeben wurde (ich unterstütze die Parameter --from und --to, mit welchen man das Quell bzw. das Zielalphabet angeben kann). Gibt es den Parameter "-", dann soll von stdin gelesen werden.

Wie sollte nun das Verhalten sein, wenn eine Datei und der Parameter "-" verwendet wird?

Code: Alles auswählen

translit --from cy --to de foobar.txt - bazbum.txt
Soll in diesem Fall zuerst foobar.txt transliteriert werden, dann alles von stdin bis Ctrl-D und zu guter letzt noch bazbum.txt? Das Programm wc scheint es zumindest so zu machen...
Habe nun, ach! Java
Python und C-Sharp,
Und leider auch Visual Basic!
Durchaus programmiert mit heissem Bemühn.
Da steh' ich nun, ich armer Tor!
Und bin so klug als wie zuvor.

Benutzeravatar
Meillo
Moderator
Beiträge: 9241
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: C: Transkriptionsprogramm mit wchar_t

Beitrag von Meillo » 02.11.2011 14:46:32

paedubucher hat geschrieben: Ich werde es nun so machen, dass das Programm von stdin liest, falls kein Dateiparameter angegeben wurde (ich unterstütze die Parameter --from und --to, mit welchen man das Quell bzw. das Zielalphabet angeben kann).
Wie waer's mit `-f' und `-t'? Das ist weniger zu tippen und die Bedeutung ist doch klar.
Wie sollte nun das Verhalten sein, wenn eine Datei und der Parameter "-" verwendet wird?

Code: Alles auswählen

translit --from cy --to de foobar.txt - bazbum.txt
Soll in diesem Fall zuerst foobar.txt transliteriert werden, dann alles von stdin bis Ctrl-D und zu guter letzt noch bazbum.txt? Das Programm wc scheint es zumindest so zu machen...
Genau so.
Use ed once in a while!

Antworten