====== Zeichensätze konvertieren ======
Siehe auch [[Dateiformate konvertieren]] und [[Byte Order Mark - BOM]]
* [[http://wiki.ubuntuusers.de/Zeichensatz-Konverter]]
==== 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
==== dos2unix ====
Wenn man unter DOS/Windows eine Textdatei erstellt, dann enthält sie am Zeilenende das //^M//-Zeichen.
Um es zu entfernen, kann man im einfachsten Fall das folgende Kommando ausführen:
# tr -d \\r < dosfile > newfile
# cat dosfile | tr -d '\r' > newfile
Es ist aber auch möglich den Befehl "dos2unix" zu verwenden und für die umgekehrte Umwandlung den Befehl "unix2dos".
Installiert werden diese Befehle in **FreeBSD** mit:
# portinstall -prO converters/dosunix
# pkg install dosunix
# pkg install dos2unix
Installiert werden diese Befehle in **Ubuntu** mit:
# apt install dos2unix
Datei in **FreeBSD** vom DOS-Format ins Unix-Format überführen:
# dosunix datei
Datei in **FreeBSD** vom Unix-Format ins DOS-Format überführen:
# unixdos datei
Installiert werden diese Befehle in **Ubuntu** mit:
# apt install tofrodos
Datei in **Ubuntu** vom DOS-Format ins Unix-Format überführen:
# fromdos datei
Datei in **Ubuntu** vom Unix-Format ins DOS-Format überführen:
# todos 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 ===
* [[http://wiki.ubuntuusers.de/Skripte/Zeichensatzkonvertierung#Bash]]
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