====== 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