Benutzer-Werkzeuge

Webseiten-Werkzeuge


zeichensaetze_konvertieren

Dies ist eine alte Version des Dokuments!


Zeichensätze konvertieren

convmv

Dieses Werkzeug dient zur Umwandlung von Dateinamen.

sed

DOS-Zeilenenden zu Unix-Zeilenenden umwandeln:

> sed -i 's/\x0D$//' DATEI 

Unix-Zeilenenden zu DOS-Zeilenenden umwandeln:

> sed -i 's/$/\r/' DATEI

iconv

iconv ist der Klassiker, er beherscht praktisch alle Zeichensätze mit denen man in Kontakt kommen könnte und erlaubt das konvertieren von einem beliebigen in einen beliebigen Zeichensatz:

> iconv -f ISO-8859-15 -t UTF-8 -o utf8datei.txt isodatei.txt

Mir ist leider kein Werkzeug bekannt, mit dem man automatisch in einem Skript, den verwendeten Zeichensatz in einer Datei erkennen kann.

Aber glücklicherweise gibt iconv immer dann eine Warnung aus, wenn es ein oder mehrere Zeichen nicht sinnvoll konvertieren konnte. Mit diesem Wissen kann man sich einen Zeichensatzdetektor (für die relevanten Fälle) selber bauen, der allerdings nur erkennen kann, welcher Zeichensatz überhauptnicht passen kann.

In diesem Beispiel wollen wir als Ergebnis ein Datei im UTF8-Format haben und wir wissen, wenn sie nicht in der UTF8-Kodierung vorliegt, dann liegt sie in der ISO-8859-1-Kodierung vor. Einen "echten" Universal-Detektor können wir so leider nicht bauen.

hier probieren wir die beiden bekannten Zeichensatzkodierungen an einer ISO-8859-1 kodierten Datei aus:

> cat /tmp/test_iso88591.txt | iconv -f ISO-8859-1 -t UTF-8 | wc
    167     371    4273

> cat /tmp/test_iso88591.txt | iconv -f UTF-8 -t UTF-8 | wc
iconv: ungültige Eingabe-Sequenz an der Stelle 119
     11       8     119

> cat /tmp/test_iso88591.txt | iconv -f ISO-8859-1 -t UTF-8 | wc -m
4194

> cat /tmp/test_iso88591.txt | iconv -f UTF-8 -t UTF-8 | wc -m
iconv: ungültige Eingabe-Sequenz an der Stelle 119
119

Kodekombinationen, die garnicht funktionieren weil sie unkültige Zeichen erzeugen würden und somit ausgeschlossen werden können, äußern sich hier mit einer Fehlermeldung.

hier probieren wir die beiden bekannten Zeichensatzkodierungen an einer UTF-8 kodierten Datei aus:

> cat /tmp/test_utf8.txt | iconv -f ISO-8859-1 -t UTF-8 | wc
    168     371    4265

> cat /tmp/test_utf8.txt | iconv -f UTF-8 -t UTF-8 | wc
    168     371    4107

> cat /tmp/test_utf8.txt | iconv -f ISO-8859-1 -t UTF-8 | wc -m
4107

> cat /tmp/test_utf8.txt | iconv -f UTF-8 -t UTF-8 | wc -m
4028

Hier gibt es keine Fehlermeldungen und so müssen wir die Dateilänge in Byte oder Zeichen messen. Richtig ist hier die kleinere Zahl, weil die Sonderzeichen im UTF-8-Zeichensatz doppelt so lang sind, wie im ISO-8859-1-Zeichensatz.

Ein "ä" belegt auf der Festplatte in UTF-8 kodiert, 16 Byte. Werden also diese 16 Byte mit ISO-8859-1 dekodiert, müssen zwei Zeichen dabei rauskommen.

Zeichensatzkodierung per Skript erkennen

Es ist aber möglich eine zutreffende Zeichensatzkodierung zu finden, wenn man ein Wort mit Sonderzeichen aus der entsprechenden Datei kennt. Dann kann man einfach alle Zeichensatzkodierungen durchprobieren, bis das Wort mit Sonderzeichen richtig lesbar ist. Genau das wird in dem folgenden Skript getan.

#!/bin/bash
#
# encoding-finder.sh
# (C) GPLv3, Stefan Wagner 2007
#
###
### In einer Datei einen bekannten (Teil-)String (z.B.: Begrüßung) suchen,
### indem alle Encodings ausprobiert werden.
###
#
# angepasst von Manfred Heins am 18. Okt. 2013
# so das nur die ISO-8859-, UTF- und WINDOWS-Zeichensatzkodierungen ausprobiert werden
#
[[ $# -ne 2 ]] && echo "Usage: ${0} DATEINAME PATTERN_MIT_UMLAUT_DER_SICHER_IN_DATEI_IST" && exit
FILE="${1}"
PATTERN="${2}"
for enc in $( iconv -l | sed 's/..$//' | egrep '8859-|UTF|WINDOWS')
do
        iconv -f "${enc}" -t UTF-8 "${FILE}" 2>/dev/null | fgrep "${PATTERN}" >/dev/null && echo "${enc}"
done | head -n1

Hier werden allerdings nur die gebräuchlichen ISO-8859- und UTF-Zeichensatzkodierungen ausprobiert und nur der erste Treffer wird ausgegeben, das ist für die automatische Verwendung in Skripten besser geeignet.

Zeichensatz_konvertieren_nach_UTF8

> vi Zeichensatz_konvertieren_nach_UTF8.sh
#!/usr/bin/env bash

#
# Dieses Skript konvertiert alle Dateien in einen anderen Zeichensatz,
# dessen Inhalt erst den angegeben Pattern enthält, wenn er konvertiert wurde.
# Der richtige Zeichensatz wird dabei durch ausprobieren ermittelt.
# Es werden hier aber NICHT alle möglichen Zeichensätze ausprobiert,
# so das nur die ISO-8859-, UTF- und WINDOWS-Zeichensatzkodierungen ausprobiert werden
#
# Meine Inspiration für dieses Skript habe ich von hier:
# http://wiki.ubuntuusers.de/Skripte/Zeichensatzkonvertierung#Bash
#
VERSION="v2013102100"

### Hilfe
[[ $# -ne 2 ]] && echo "Usage: ${0} DATEINAME PATTERN_MIT_UMLAUT_DER_SICHER_IN_DATEI_IST" && exit

### alle brauchbaren Zeichensatzkodierungen ermitteln
DATEIPFAD="${1}"
PATTERN="${2}"
DATEIVERZ="$(dirname "${DATEIPFAD}")"
DATEINAME="$(basename "${DATEIPFAD}")"
cd ${DATEIVERZ}/ || exit 1
ZEICHENSATZKODIERUNGEN="$(for enc in $(iconv -l | sed 's/..$//' | egrep -i '8859-|UTF|WINDOWS')
do
        iconv -f "${enc}" -t UTF-8 "${DATEINAME}" 2>/dev/null | fgrep "${PATTERN}" >/dev/null && echo "${enc}"
done)"

#------------------------------------------------------------------------------#
### weitere Tests

### Werte für den Plausibilitätstest generieren
AUSGABE="$(
for KODIERUNG in ${ZEICHENSATZKODIERUNGEN}
do
        if [ "${KODIERUNG}" != "UTF-8" -a "${KODIERUNG}" != "UTF8" ] ; then
                DEKODIERTERINHALT="$(iconv -f ${KODIERUNG} -t UTF-8 ${DATEINAME} 2>/dev/null)"
                if [ "${?}" == "0" ] ; then
                        ZEICHENANZAHL="$(echo "${DEKODIERTERINHALT}" | wc -m)"
                        echo "${ZEICHENANZAHL} ${KODIERUNG}" #>/dev/null
                else
                        echo "'${KODIERUNG}'" >/dev/null
                fi
        else
                echo "'${KODIERUNG}': Die Datei ist bereits in UTF-8 kodiert." >/dev/null
        fi
done
)"

### Plausibilitätstest ermittelt die passenste Zeichensatzkodierung
TREFFER="$(echo "${AUSGABE}" | awk '{print $1}' | sort -n | head -n1)"
QUELLZS="$(echo "${AUSGABE}" | egrep "^${TREFFER} " | awk '{print $2}' | head -n1)"

### Konvertierung
if [ -n "${QUELLZS}" ] ; then
        iconv -f ${QUELLZS} -t UTF-8 -o neu_utf8.txt ${DATEINAME} && (sed -i 's/[Ii][Ss][Oo][-_]*8859[-][0-9][0-9]*[Ee]*[:]*[0-9]*/UTF-8/g' neu_utf8.txt;mv -v ${DATEINAME} ${DATEINAME}_$(date +'%Y%m%d%H%M%S') && mv -v neu_utf8.txt ${DATEINAME})
fi

Wenn wir beispielsweise zwei Dateien nehmen, eine dessen Inhalt ISO-8859-1 kodiert ist und eine, die UTF-8 kodiert ist:

> ls -lh
-rw-r--r-- 1 fritz fritz 4,1K Okt 18 12:18 test_iso88591.txt
-rw-r--r-- 1 fritz fritz 4,1K Okt 18 12:18 test_utf8.txt

Dann wird von diesem Skript nur die ISO-8859-1 kodierte Datei konvertiert:

> ./Zeichensatz_konvertieren_nach_UTF8.sh test_iso88591.txt 'Begrüßung'
"test_iso88591.txt" -> "test_iso88591.txt_20131018165849"
"neu_utf8.txt" -> "test_iso88591.txt"

> ./Zeichensatz_konvertieren_nach_UTF8.sh test_utf8.txt 'Begrüßung'

> ls -lh
-rw-r--r-- 1 fritz fritz 4,2K Okt 18 16:58 test_iso88591.txt
-rw-r--r-- 1 fritz fritz 4,1K Okt 18 12:18 test_iso88591.txt_20131018165849
-rw-r--r-- 1 fritz fritz 4,1K Okt 18 12:18 test_utf8.txt
/home/http/wiki/data/attic/zeichensaetze_konvertieren.1460501402.txt · Zuletzt geändert: von 127.0.0.1