michahe
Anmeldungsdatum: 12. Dezember 2013
Beiträge: 857
|
Hallo, in einer txt-Datei möchte ich alle ASCII-Code 194 durch ASCII-Code 32 (BLANK) ersetzen. Wie kann ich in sed die ASCII-Codes definieren? Der folgende Code (für das 194-Zeichen mit Copy&Paste) funktioniert, ist aber nicht lesbar
sed 's/ / /g' qq.txt > qq2.txt Danke, Michael
|
shiro
Anmeldungsdatum: 20. Juli 2020
Beiträge: 1214
|
michahe schrieb: sed ... 194-Zeichen ... in Blank (32)
Da 194 dezimal = C2 hexadezimal ist, wäre der sed Befehl wie folgt zu nutzen:
sed "s/\xC2/ /g" qq.txt > qq2.txt
oder
cat qq.txt | tr $'\xC2' " " > qq2.txt
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 13131
|
shiro schrieb:
cat qq.txt | tr $'\xC2' " " > qq2.txt
Wir haben mal wieder einen Useless Use of cat Gewinner. ☺ | tr $'\xC2' ' ' < qq.txt > qq2.txt
|
|
michahe
(Themenstarter)
Anmeldungsdatum: 12. Dezember 2013
Beiträge: 857
|
Danke, damit ich etwas mehr lerne: Es ist wohl unmöglich die ASCII-Codes zu nutzen, also in der Art
sed 's/\\194\/\\032\/g' qq.txt > qq2.txt ## Code ist FALSCH!
Für mich wäre das besser lesbar (verständlich)?
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11237
Wohnort: München
|
michahe schrieb: Danke, damit ich etwas mehr lerne: Es ist wohl unmöglich die ASCII-Codes zu nutzen, also in der Art
sed 's/\\194\/\\032\/g' qq.txt > qq2.txt ## Code ist FALSCH!
Für mich wäre das besser lesbar (verständlich)?
Das kann man machen, wenn man die Manpage gelesen hat und die richtige Syntax wählt: https://www.gnu.org/software/sed/manual/html_node/Escapes.html - das wäre dann s/\d194/\d032/g Nebenbei bemerkt ist ASCII ein 7-Bit Encoding und wenn du einen Wert > 127 hast, dann hast du es vermutlich mit einem der vielen 8-Bit Encodings zu tun, so dass man sich abhängig davon, was das Ziel der Aktion ist überlegen kann, ob man sich das Leben nicht leichter macht, wenn man das 8-Bit Encoding nach UTF-8 konvertiert statt Informationen zu verlieren, wenn man die Zeichen durch Spaces ersetzt.
|
michahe
(Themenstarter)
Anmeldungsdatum: 12. Dezember 2013
Beiträge: 857
|
Danke, das
`s/\d194/\d032/g`
sieht doch sehr gut aus und funktioniert! funktioniert aber leider nicht:
sed 's/ / /g' # liefert 112,1 kg (wie gewünscht)
sed 's/\xC2/ /g' # liefert 112,1 kg (erstes Zeichen 032, zweites Zeichen 194)
sed 's/\d194/\d032/g' # liefert 112,1 kg (erstes Zeichen 032, zweites Zeichen 194) Nebenbei bemerkt ist ASCII ein 7-Bit Encoding und wenn du einen Wert > 127 hast, dann hast du es vermutlich mit einem der vielen 8-Bit Encodings zu tun, so dass man sich abhängig davon, was das Ziel der Aktion ist überlegen kann, ob man sich das Leben nicht leichter macht, wenn man das 8-Bit Encoding nach UTF-8 konvertiert statt Informationen zu verlieren, wenn man die Zeichen durch Spaces ersetzt.
Das verstehe ich nicht: Wenn ich das Zeichen mit CALC analysiere, liefert es CODE = 194 und UNICODE = 160. Schau ich die Datei mit Firefox an,wird Seiteninformationen (CTRL-I) > Textcodierung = UTF8 geliefert. UTF8 behauptet auch KATE mit Extras > Kodierung > UTF. Ein Verlust (von was?) ist nicht zu erwarten, da es immer ein Trennzeichen zwischen einer Zahl und einer Maßeinheit ist.
112,1 kg
Was muss ich noch im Zusammenhang mit Encodings und Umwandlung lernen?
|
michahe
(Themenstarter)
Anmeldungsdatum: 12. Dezember 2013
Beiträge: 857
|
als Schnelltest (das 194-Zeichen markiert:
$ echo '112,1 kg' | sed 's/\d194/\d032/g'
112,1 �kg
$ echo '112,1 kg' | sed 's/ /\d032/g'
112,1 kg
Was mache ich falsch?
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11237
Wohnort: München
|
Also ist das ein non-breaking Space (HTML  , Unicode 0xa0 ) - immer diese typographischen Banausen, da gehört ein Schmales Leerzeichen hin 😇 Vorab: Da das Forum wohl gerne den non-breaking space verschluckt, erzeuge den String durch etwas python-Code, damit das leichter mit Copy & Paste handzuhaben ist. Deine Shell läuft standardmäßig mit dem UTF-8 Zeichensatz, dementsprechend ist der Codepoint 160 und da der einen Wert > 127 hat, wird das Zeichen mit zwei Bytes repräsentiert, wie man gut mit xxd sehen kann:
$ python -c "print(chr(160), end='')" | xxd
00000000: c2a0 .. michahe schrieb: als Schnelltest (das 194-Zeichen markiert:
$ echo '112,1 kg' | sed 's/\d194/\d032/g'
112,1 �kg
Was mache ich falsch?
$ python3 -c "print(f'112,1{chr(160)}kg', end='')" | sed 's/\d194/\d032/g' | xxd
00000000: 3131 322c 3120 a06b 67 112,1 .kg 192 = 0xc2 - d.h. mit deinem sed-Befehl ersetzt du das erste Byte aus den zwei Bytes für das geschützte Leerzeichen und es bleibt ein Wert von 0xa0 = 160 stehen, weshalb du danach ein Leerzeichen gefolgt von einem nicht darstellbaren Zeichen (da das Byte einen Wert > 127 hat, was bei UTF-8 für das erste Byte eines Zeichens nicht zulässig ist) siehst. Wenn du das Zeichen direkt angibst, stehen da tatsächlich zwei Bytes - das kann man z.B. so gut sehen (das 0x0a ist der Zeilenumbruch, den sed anhängt):
$ sed 's/.*/ /' <<< "a" | xxd
00000000: c2a0 0a ... Wenn du also mit sed und dezimalen Angaben für den Codepoint arbeiten willst, dann musst du die Bytes angeben, die du ersetzen willst, nicht den Code des Zeichens (wenn es mehr als ein Byte breit ist) - das ist das gängige Problem bei Programmen, die aus Zeiten stammen, als es nur Zeichensätze mit 7 oder 8 Bit gab (und allgemein eine Herausforderung bei Programmen, die in Low-Level Sprachen wie in C/C++ geschrieben sind, weil da ein char nur ein Byte groß ist):
$ python3 -c "print(f'112,1{chr(160)}kg', end='')" | sed 's/\d194\d160/\d032/g' | xxd
00000000: 3131 322c 3120 6b67 112,1 kg Deswegen arbeite ich gerne mit Python3, weil das Handling von Encodings einfacher ist - z.B. wäre das das Äquivalent zum vorangegangenen sed-Befehl (Python3 arbeitet intern mit Unicode-Codepoints und nutzt standardmäßig UTF-8 als Encoding für die Ein- und Ausgabe):
| #!/usr/bin/env python3
import fileinput
for line in fileinput.input():
print(line.replace(chr(160), " "), end='')
|
Und falls man eine Datei mit einem abweichenden Encoding hat, gibt man das der fileinput.input() Methode als Argument mit, also z.B. fileinput.input(encoding='latin-1') , dann fällt da schönes UTF-8 mit der gewünschten Ersetzung raus.
|
michahe
(Themenstarter)
Anmeldungsdatum: 12. Dezember 2013
Beiträge: 857
|
Vielen Dank seahawk1986, leider komme ich nicht mit:
Kann ich kein PYTHON; ich hatte mit viel Vorfreude einen Kurs belegt und bin dann schon an der Umstellung PYTHON2 → PYTHON3 und dem Fiddle im Kurs gescheitert; das versuche ich noch einmal, brauche dazu aber mehr Zeit. Habe ich ein laufendes BASH-Programm mit einigen zig Zeilen Code, in das dieser Schnipsel hinein gehört.
Kann ich das nicht "irgendwie" mit sed lösen, z.B.
$ echo '112,1 kg' | sed 's/\d194/\d032/g'
112,1 �kg
und dann das Ergebnis mit
sed 's/\d032\d160/\d032/g
behandeln? (M)Ein "blinder" Versuch:
$ echo '112,1 kg' | sed 's/\d194/\d032/g' | sed 's/\d032\d160/\d032/g'
112,1 kg
Was meinst Du?
|
shiro
Anmeldungsdatum: 20. Juli 2020
Beiträge: 1214
|
michahe schrieb: $ echo '112,1 kg' | sed 's/\d194/\d032/g' | sed 's/\d032\d160/\d032/g'
112,1 kg
Die beiden sed kannst du zu einem zusammenfassen. Wenn du aber von UTF-8 Codierung zu Latin1 transformieren willst, kannst du auch iconv nutzen. Dabei werden die mehrere Byte langen UTF-8 Zeichen in ein Byte gewandelt:
$ echo '112,1 kg' | sed 's/\d194\d160/\d032/g' | xxd
00000000: 3131 322c 3120 6b67 0a 112,1 kg.
$ echo '112,1 kg' | iconv -f utf-8 -t | xxd
00000000: 3131 322c 31a0 6b67 0a 112,1.kg.
$ echo '112,1 kg' | iconv -f utf-8 -t | tr $'\xa0' ' ' | xxd
00000000: 3131 322c 3120 6b67 0a 112,1 kg.
|
michahe
(Themenstarter)
Anmeldungsdatum: 12. Dezember 2013
Beiträge: 857
|
shiro schrieb:
Danke, aber was ist denn das
| xxd
?
|
shiro
Anmeldungsdatum: 20. Juli 2020
Beiträge: 1214
|
michahe schrieb: Danke, aber was ist denn das "xxd"?
xxd ist ein Hex-Dump Befehl, der dir die Ergebnisse Byte für Byte links und rechts in Textform darstellt. Wenn du andere tools wie "od" lieber magst, nimm diese zum anschauen der Ergebnisse. PS: Ich sehe grade, dass ich beim iconv den "-t" switch nicht vollständig angegeben habe.
statt: iconv -f utf-8 -t
besser: iconv -f utf-8 -t l1
|
michahe
(Themenstarter)
Anmeldungsdatum: 12. Dezember 2013
Beiträge: 857
|
(M)Ein "blinder" Versuch:
$ echo '112,1 kg' | sed 's/\d194/\d032/g' | sed 's/\d032\d160/\d032/g'
112,1 kg
funktioniert so in der Konsole, aber nicht wenn ich ihn auf eine txt-Datei anwende. Falls mir jemand den richtigen Weg zeigen möchte, ein Testfile ist beigefügt. Vorerst bleibe ich bei der (nicht lesbaren, aber funktionerenden) Version mit den direkt einkopierten Zeichen:
sed 's/ / /g' "INput" > "OUTput"
Ebenso hilt mir iconf nicht, das 194-Zeichen bleibt erhalten nach
iconv -f utf-8 -t l1 Ascii194.txt > Ascii195.txt
- Ascii194.txt (44 Bytes)
- Download Ascii194.txt
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11237
Wohnort: München
|
Es macht IMHO keinen Sinn das zweizeitig zu ersetzen - das funktioniert für mich in einem Rutsch mit der angehängten Datei:
$ xxd < 9260557-Ascii194.txt
00000000: 4475 6d6d 7920 2020 2020 2031 3132 2c31 Dummy 112,1
00000010: c2a0 6b67 0a56 6572 7375 6368 2020 2020 ..kg.Versuch
00000020: 2020 3233 322c 35c2 a06b 670a 232,5..kg.
$ sed 's/\d194\d160/\d032/' 9260557-Ascii194.txt | xxd
00000000: 4475 6d6d 7920 2020 2020 2031 3132 2c31 Dummy 112,1
00000010: 206b 670a 5665 7273 7563 6820 2020 2020 kg.Versuch
00000020: 2032 3332 2c35 206b 670a 232,5 kg.
|
michahe
(Themenstarter)
Anmeldungsdatum: 12. Dezember 2013
Beiträge: 857
|
OK, aber wie lautet der Befehl, aus der Ascii194.txt eine Ascii195.txt zu erzeugen, in der die 194 Zeichen durch 032-Zeichen (BLANK) ersetzt sind?
|