bash: printf und Umlaute

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
Benutzeravatar
JaKlaRo
Beiträge: 121
Registriert: 06.03.2008 15:00:00
Lizenz eigener Beiträge: GNU General Public License
Kontaktdaten:

bash: printf und Umlaute

Beitrag von JaKlaRo » 15.01.2010 14:26:39

Hallo,
printf verhält sich etwas seltsam, wenn in einem String Umlaute enthalten sind, Ein Beispiel:

Code: Alles auswählen

#! /bin/bash

a="ohne Umlaut"
b="größere Ärgernisse"
c="kleinere Ärgernisse"
d="auch ohne Umlaut"

printf "\t|%-22s|\n" "$a"
printf "\t|%-22s|\n" "$b"
printf "\t|%-22s|\n" "$c"
printf "\t|%-22s|\n" "$d"
Ausgabe:

Code: Alles auswählen

	|ohne Umlaut           |
	|größere Ärgernisse |
	|kleinere Ärgernisse  |
	|auch ohne Umlaut      |
locale auf dem System: de_DE.UTF-8
Gibt es für das Problem ein simple Lösung oder muß ich alle Umlaute in den Strings zählen?

Grüße
JaKlaRo

yeti

Re: bash: printf und Umlaute

Beitrag von yeti » 15.01.2010 15:05:55

Ist das nicht eher eine Wanze in GLibc?

Code: Alles auswählen

(yeti@xs3:2)~$ echo $LANG 
de_DE.UTF-8
(yeti@xs3:2)~$ cat pf.c 
#include <stdio.h>

main() {
  printf("|%-10s|\n","ä");
  printf("|%-10s|\n","äö");
  printf("|%-10s|\n","äöü");
}
(yeti@xs3:2)~$ gcc pf.c 
(yeti@xs3:2)~$ ./a.out 
|ä        |
|äö      |
|äöü    |

Benutzeravatar
JaKlaRo
Beiträge: 121
Registriert: 06.03.2008 15:00:00
Lizenz eigener Beiträge: GNU General Public License
Kontaktdaten:

Re: bash: printf und Umlaute

Beitrag von JaKlaRo » 15.01.2010 23:13:52

yeti hat geschrieben:Ist das nicht eher eine Wanze in GLibc?
Ich denke nicht denn:

Code: Alles auswählen

$ echo "aou" | wc -c
4
$ echo "äöü" | wc -c
7

yeti

Re: bash: printf und Umlaute

Beitrag von yeti » 16.01.2010 00:12:50

JaKlaRo hat geschrieben:
yeti hat geschrieben:Ist das nicht eher eine Wanze in GLibc?
Ich denke nicht denn:

Code: Alles auswählen

$ echo "aou" | wc -c
4
$ echo "äöü" | wc -c
7
wc ist etwa nicht in C mit Hilfe von GLibc geschrieben?
Ich denke doch!

Benutzeravatar
GoKi
Beiträge: 2068
Registriert: 04.07.2003 23:08:56
Lizenz eigener Beiträge: MIT Lizenz

Re: bash: printf und Umlaute

Beitrag von GoKi » 16.01.2010 00:15:38

Afaik bezieht sich die Angabe bei dem String laut Posix bei printf auf die Anzahl Bytes. Bei Unicode entspricht die Anzahl Bytes nicht zwangsläufig der Anzahl ausgegebener Zeichen.Ob das jetzt so super sinnvoll ist, ist eine andere Sache.
Wenn ich mich recht erinnere zählt wprintf die Anzahl Zeichen statt Bytes (Gerade keine man-pages verfügbar). Also sollte folgendes besser aussehen:

Code: Alles auswählen

#include <wchar.h>
#include <stdio.h>
#include <locale.h>
main() {
  setlocale(LC_ALL, "");
  wprintf(L"|%-10ls|\n", L"ä");
  wprintf(L"|%-10ls|\n", L"äö");
  wprintf(L"|%-10ls|\n", L"äöü");
}
MfG GoKi
:wq

Benutzeravatar
ThorstenS
Beiträge: 2875
Registriert: 24.04.2004 15:33:31

Re: bash: printf und Umlaute

Beitrag von ThorstenS » 16.01.2010 21:21:25

Du musst also die Zeichen zählen, die nicht [a-z][A-Z] und Sonderzeichen darstellen und zur gewünschten Länge addieren.
quick`n very dirty:

Code: Alles auswählen

#!/bin/bash
LAENGE=22
a="ohne Umlaut"
A=$(echo $a | tr -d "[a-z][A-Z] .-")
b="größere Ärgernisse"
B=$(echo $b | tr -d "[a-z][A-Z] .-")
c="kleinere Ärgernisse"
C=$(echo $c | tr -d "[a-z][A-Z] .-")
d="auch ohne Umlaut"
D=$(echo $d | tr -d "[a-z][A-Z] .-")

printf "\t|%-$(($LAENGE+${#A}))s|\n" "$a"
printf "\t|%-$(($LAENGE+${#B}))s|\n" "$b"
printf "\t|%-$(($LAENGE+${#C}))s|\n" "$c"
printf "\t|%-$(($LAENGE+${#D}))s|\n" "$d"
Ausgabe:

Code: Alles auswählen

$ sh utf8-ergänzungen
        |ohne Umlaut           |
        |größere Ärgernisse    |
        |kleinere Ärgernisse   |
        |auch ohne Umlaut      |
Die Ersetzungen sind natürlich dürftig und das 'Programm' schreit nach einer Funktion zum Berechnen.

EDIT:
Das echo und tr oben kann man natürlich mit Shellmittel abbilden. Folgendes ergibt 3, weil ö,ß und Ä ersetzt werden:

Code: Alles auswählen

b="größere Ärgernisse"
Laengeb=${#b}
StringOhneUmlaute=${b//[ööüßÄÜÖ]/}
LaengeStringOhneUmlaute=${#StringOhneUmlaute}

DIFF=$((Laengeb - LaengeStringOhneUmlaute))
echo $DIFF
3

Antworten