Zeichen ersetzen

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
guennid

Zeichen ersetzen

Beitrag von guennid » 03.02.2019 10:27:53

Ich möchte via script drei Zeichen, sagen wir a,b,c in einer Textdatei komplett durch sagen wir x, y, z ersetzen, also jedes a durch x, jedes b durch y und jedes c durch z ersetzen. Wie macht man das, möglichst in einem Durchgang? Ich nehme an, sed muss benutzt werden, aber bisher habe ich keine Anleitung gefunden, die ich zweifelsfrei auf meine Aufgabe beziehen konnte.

Grüße, Günther

eggy
Beiträge: 3331
Registriert: 10.05.2008 11:23:50

Re: Zeichen ersetzen

Beitrag von eggy » 03.02.2019 11:26:27

Sed kann, muss aber nicht.
Wenn es Dir nur um 1:1 Ersetzungen geht, nimm tr, das ist in so einfachen Fällen leichter zu benutzen.

Code: Alles auswählen

cat datei.txt | tr 'abc' 'yxz' 

guennid

Re: Zeichen ersetzen

Beitrag von guennid » 03.02.2019 11:48:43

Danke für den Versuch, funktioniert aber nicht. In der vorliegenden Form des Kommandos wird jedes zu ersetzende Zeichen durch das letzte im Ersatzstring ersetzt.

eggy
Beiträge: 3331
Registriert: 10.05.2008 11:23:50

Re: Zeichen ersetzen

Beitrag von eggy » 03.02.2019 11:56:26

Komisch. Hier sieht das so aus:

Code: Alles auswählen

$ echo "abc abc acb bca cba" && echo "abc abc acb bca cba" | tr 'abc' 'xyz'
abc abc acb bca cba
xyz xyz xzy yzx zyx

guennid

Re: Zeichen ersetzen

Beitrag von guennid » 03.02.2019 12:07:08

Hmm, ich hätte wohl sagen sollen, dass die Zeichen als einzelne auftreten. Konkret geht's z.B. um typografische Anführungszeichen (gibt's wohl nur im Deutschen?), die bei jedem Auftauchen ersetzt werden sollen. Zum Testen so: "Gänsefüsschen unten" sollen, wo immer sie auftauchen, durch ein 'x', "Gänsefüßchen oben" durch ein 'y' ersetzt werden. Später weder natürlich die typografischen durch die international(?) gebräuchlichen Anführungszeichen ersetzt.

Ob's bei drei Zeichen bleibt, weiß ich noch nicht, aber wenn ich's bei dreien geschafft habe, werde ich das wohl erweitern können.

eggy
Beiträge: 3331
Registriert: 10.05.2008 11:23:50

Re: Zeichen ersetzen

Beitrag von eggy » 03.02.2019 12:32:25

Dass es nicht geklappt hat, liegt da eher an den Anführungszeichen. tr ist für ganz einfache Sachen super, bei komplizierterem teilweise leider nicht, hätt ich vielleicht erwähnen sollen, sorry.

Versuchs mal damit:

Code: Alles auswählen

echo "„123“ 321" | sed "s_„_a_g; s_“_b_g; "
Ich nehm als Trenner gerne den Unterstrich, liest sich m.E. besser, in vielen Tutorials wirst Du ein Minus an der Stelle finden, dadurch nicht verwirren lassen.

Edit: nach dem letzten Semikolon kannst Du weitere Pattern der Form s_was_gegenwas_g; einfügen, das s steht dabei für ersetzen und das g für global, also nicht nur den ersten Treffer.

guennid

Re: Zeichen ersetzen

Beitrag von guennid » 03.02.2019 12:58:41

Danke sehr! :THX:

Mich verwirren weniger die Unterstriche, als die beiden "normalen" Anführungszeichen beim sed, deren Bedeutung mir noch unklar ist.

Unabhängig davon versuch' ich mal, mein Verständnis in menschlicher Sprache :wink: zu formulieren:
s bedeutet etwa "ersetz' was"
die "Gänsefüßchen unten" geben das "was" an, das ersetzt werden soll: ergo: sind das zu ersetzende Zeichen.
a ist das Ersatzzeichen
g sagt, dass "jedes" Vorkommen ersetzt werden soll
Das 1. Semikolon sagt: es kommt noch was
zwischen erstem und zweitem Semikolon steht dann die nächste Komplett-Ersetzung von "Gänsefüßchen oben" zu b

Was sagt das 2.Semikolon?
Warum das Ganze in Anführungszeichen?

Auf eine Datei angewendet scheint es nach erstem Test in dieser Form zu funktionieren:

Code: Alles auswählen

sed "s_„_a_g; s_“_b_g; " test.txt
Ich hatte allerdings in test.txt nur einen kurzen einzeiligen Text mit einmaligem Vorkommen der typografischen Anführungszeichen stehen.

Grüße, Günther

eggy
Beiträge: 3331
Registriert: 10.05.2008 11:23:50

Re: Zeichen ersetzen

Beitrag von eggy » 03.02.2019 13:17:09

Das zweite Semikolon ist überflüssig, ausser Du willst danach noch ein drittes Pattern anfügen.
Die Anführungszeichen kann man oftmals weglassen, aber wenn Du mehrere Pattern hintereinander benutzt, kann es Dir passieren, dass die Shell denkt, das Semikolon sei die Beendung des Befehls und es folgt ein normaler Befehl für sie und nicht, dass das folgende auch noch für sed sei. Ich hab mir irgendwann einfach angewöhnt sowas im Zweifelsfall einfach mitzutippen.

guennid

Re: Zeichen ersetzen

Beitrag von guennid » 03.02.2019 13:22:52

Super! :THX:

Jetzt wird's noch einen Tick haariger: Langer Bindestrich. Den krieg ich im Terminal gar nicht eingegeben und auch wenn ich das sed-Kommando scripte, den langen Bindestrich reinkopiere, wird der bei der Ausführung offenbar nicht als zu ersetzend erkannt.

Grüße, Günther

eggy
Beiträge: 3331
Registriert: 10.05.2008 11:23:50

Re: Zeichen ersetzen

Beitrag von eggy » 03.02.2019 14:18:47

https://de.wikipedia.org/wiki/Halbgeviertstrich ?
Bei mir kann ich den direkt in die Shell kopieren (im Browser einfach nur markieren, in der Konsole dann mit der mittleren Maustaste einfügen), ob das auch bei Dir geht, hängt von Windowmanager, Terminal, Shell, Mondphase, etc ab.
Falls nicht, die entsprechende UTF-8 Codierung nehmen und es mal damit versuchen.

Code: Alles auswählen

echo 1 | sed s_1_–_g; 
echo 1 | sed s_1_$'\u2013'_g; 
Und falls das auch nichts wird, warten bis Meillo vorbei liest, der kennt sich da besser aus :mrgreen:

wanne
Moderator
Beiträge: 7462
Registriert: 24.05.2010 12:39:42

Re: Zeichen ersetzen

Beitrag von wanne » 03.02.2019 14:21:09

Gedankenstriche – machst du mit AltGr+-. Der hat dann die Länge von ½-em. Allerdings gibt es dann noch den doppelt so langen Gedankenstrich —, Den Bindestrich, Den Bindestrich, der nicht trennt, den waagrechten Strich, den Gedankenstrich ohne feste Länge, den ASCII Gedanken-/Beindestrich...
Ich nehme an, du verwendest 2 verschiedene.
rot: Moderator wanne spricht, default: User wanne spricht.


guennid

Re: Zeichen ersetzen

Beitrag von guennid » 03.02.2019 15:05:21

Hallo wanne!
Ich will keine "langen" Bindestriche "machen"/malen, sprich setzen, ich will sie ersetzen, was immer für *Geviert*-Striche das sein mögen. :wink:

Danke eggy, das hilft wieder weiter. Die verlinkten Seiten hatte ich bereits eingesehen. Jetzt bemerke ich, dass auch utf-8-Nummern dort angegeben werden. Da ich die Zeichen als solche bisher weder via Tastatur noch Kopieren in mein sed-Kommando/Script hineinbekommen habe, werde ich es mit den Nummern versuchen.Für meine Zwecke müsste ich dein zweites Kommando wohl "umdrehen", also:

Code: Alles auswählen

s_$'\u2013'_1
- richtig?
Zuletzt geändert von guennid am 03.02.2019 15:11:36, insgesamt 1-mal geändert.

eggy
Beiträge: 3331
Registriert: 10.05.2008 11:23:50

Re: Zeichen ersetzen

Beitrag von eggy » 03.02.2019 15:08:23

Was ersetzt werden soll vorne, wodurch ersetzt werden soll dahinter - ggfs das g für global nicht vergessen.
Und ausprobieren wäre schneller gegangen als fragen ;)

guennid

Re: Zeichen ersetzen

Beitrag von guennid » 03.02.2019 15:14:28

Und ausprobieren wäre schneller gegangen als fragen ;)
Nur, wenn ich richtig lag.

Ich bin nicht so für Schnelligkeit, mehr für "Sicherheit"/Umständlichkeit. :wink:

Wird nix.
Das hier habe ich erfolglos versucht:
sed "s_$'\u2013'_+_g; " test.txt. Ich kriege bei wikipedia nur eine weitere UTF-8-Nummer, die sich zweifelsfrei einem dieser "Gedankenstriche" zuordnen ließe, u. zwar in der Form: U+2014. Wie kriege ich raus, welches utf-8-Zeichen definitiv in meinem Beispieltext steckt?

RobertDebiannutzer
Beiträge: 385
Registriert: 16.06.2017 09:52:36

Re: Zeichen ersetzen

Beitrag von RobertDebiannutzer » 03.02.2019 17:35:27

Ich würde folgendes Vorgehen vorschlagen:

Code: Alles auswählen

$ echo '–' | hd
00000000  e2 80 93 0a                                       |....|
00000004
$ echo '–' | sed "s_\xe2\x80\x93_+_g"
+
Den Gedankenstrich habe ich in LibreOffice erzeugt und ins Terminal kopiert (urxvt). Du kannst auch den UTF-8-Code auf mehreren Websites im Internet nachschauen. Dort findest Du dann auch die (englischen) Namen für das entsprechede Zeichen (z.B. "EN DASH" in diesem Fall).
Umgekehrt kann z.B. printf auch aus Unicode-Codes Zeichen machen (s. manpage von printf).

EDIT: Ist mir noch eingefallen: Wahrscheinlich unterstützen nicht alle Varianten von sed hex-Zeichen. Ich nutze GNU sed aus stretch.
Bei meinem sed und meinem Terminal geht sogar:

Code: Alles auswählen

$ echo '–' | sed "s_–_+_g"
+

guennid

Re: Zeichen ersetzen

Beitrag von guennid » 03.02.2019 19:25:32

Das mit den Tastatureingaben, bzw copy+paste ist halt so'ne Sache, je nachdem wo du was eintippst. Giuckst du hier (1). Ich habe inzwischen vier solcher für mich kritischen Zeichen entdeckt und kann die auch via copy+paste mit sed händeln. eggys Schnipsel ist da schon was sehr Geeignetes. Aber schöner wäre halt, man könnte dem sed einen eindeutigen utf-8-code zum Ersetzen mitgeben statt das, was man da zu sehen glaubt, z.B. einen "Gedankenstrich", was immer der jeweilige Leser für einen solchen halten mag, hier also AltGr+-, bzw Strg+shift+2013, eingegeben im Terminal (übrigens das gleiche das du benutzt]. :wink:
Und da war eggys Syntax wohl nicht die zielführende. Aber Meillo interessiert''s vielleicht nicht. :wink:

(1) viewtopic.php?f=12&t=171239&hilit=utf+8

Benutzeravatar
RootRat
Beiträge: 29
Registriert: 03.06.2016 06:37:12

Re: Zeichen ersetzen

Beitrag von RootRat » 04.02.2019 04:04:12

Aber schöner wäre halt, man könnte dem sed einen eindeutigen utf-8-code zum Ersetzen mitgeben statt das, was man da zu sehen glaubt
Warum machst du das denn nicht?

Suche dir den Code fuer die Zeichen raus, beispielsweise von dieser Seite:
https://www.utf8-chartable.de/unicode-u ... pl?utf8=0x
und packe dir fuer jeden langen oder kurzen Bindestrich den Wert in eine
Variabel.
Mit sed kannst du diese dann zusammenfassen und mit nur einem Ersatzeichen
austauschen.
Einfacher geht es nicht.

Ein Beispiel, quick and dirty:

Code: Alles auswählen

#!/usr/bin/env bash

A=$(printf "\xE2\x96\x88")
B=$(printf "\xe2\x98\x8e")
C=$(printf "\xe2\xa8\x81")
D=$(printf "\x5e")
E=$(printf "\x22")
# usw.

echo $A $B $C $D $E                              # Zeige Variableninhalt

text="ab-█-⨁-☎-cd ^ef-█-g"                      # Testtext

sed "s/[$A$B$C]/*/g;s/\\$D/\\$E/g" <<<$text      # Zeichenersetzung

###  Ergebnis:  ab-*-*-*-cd "ef-*-g


# Erklaerung:

# s/[$A$B$C]/*/g => Suche (zusammengefasst) bestimmte Sonderzeichen und ersetze
# alle Vorkommen mit nur einem anderem Zeichen (hier mit Stern).

# s/\\$D/\\$E/g  => Suche Circumflex accent und ersetze mit Quotation mark.
# Quotation mark Variabel und aehnliche muessen gesondert escaped werden
# (Doppelter backslash).

# sed string muss in Quotation marks gesetzt werden, damit die Shell die
# Variabel(n) expandieren kann. 

eggy
Beiträge: 3331
Registriert: 10.05.2008 11:23:50

Re: Zeichen ersetzen

Beitrag von eggy » 04.02.2019 04:34:20

guennid hat geschrieben: ↑ zum Beitrag ↑
03.02.2019 19:25:32
eggys Schnipsel ist da schon was sehr Geeignetes. Aber schöner wäre halt, man könnte dem sed einen eindeutigen utf-8-code zum Ersetzen mitgeben statt das,
aus einem "meiner Schnipsel":
eggy hat geschrieben: ↑ zum Beitrag ↑
03.02.2019 14:18:47

Code: Alles auswählen

echo 1 | sed s_1_$'\u2013'_g; 
Was das \u2013 bedeutet, findet man übrigens da: https://en.wikipedia.org/wiki/List_of_U ... de_symbols

Benutzeravatar
Meillo
Moderator
Beiträge: 8813
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Zeichen ersetzen

Beitrag von Meillo » 04.02.2019 06:06:11

guennid hat geschrieben: ↑ zum Beitrag ↑
03.02.2019 19:25:32
Aber Meillo interessiert''s vielleicht nicht. :wink:
Den Meillo interessiert's gerade nicht, weil die technische Loesung schon vorliegt. ;-)
guennid hat geschrieben: ↑ zum Beitrag ↑
03.02.2019 19:25:32
einen "Gedankenstrich", was immer der jeweilige Leser für einen solchen halten mag
Das ist der Knackpunkt beim Verstaendnis. Dein Wunsch (``was immer der jeweilige Leser fuer einen solchen halben mag'') ist natuerlich unmoeglich, weil woher soll die Software wissen, was derjeweilige Leser fuer einen haelt? Was die Software am ehesten in diese Richtung bieten koennte, waeren Aequivalenzklassen in denen alle Gedankenstriche, die der jeweilige Sprachraum (!) fuer solche haelt, zusammengefasst werden, aber ob das in den Locales umgesetzt ist, weiss ich nicht (ich vermute eher, dass nicht). Folglich bleibt dir nur, selber genau aufzulisten, welche Unicode-Codepoints (Zeichen) du ersetzen willst und die mittels UTF-8-Escape anzugeben. Das haben die anderen schon vorgeschlagen ... darum kann ich mich hier gemuetlich zuruecklehnen und mitlesen. ;-)
Use ed once in a while!

eggy
Beiträge: 3331
Registriert: 10.05.2008 11:23:50

Re: Zeichen ersetzen

Beitrag von eggy » 04.02.2019 07:10:23

Meillo hat geschrieben: ↑ zum Beitrag ↑
04.02.2019 06:06:11
Was die Software am ehesten in diese Richtung bieten koennte, waeren Aequivalenzklassen in denen alle Gedankenstriche, die der jeweilige Sprachraum (!) fuer solche haelt, zusammengefasst werden, aber ob das in den Locales umgesetzt ist, weiss ich nicht (ich vermute eher, dass nicht).
Teilweise/Vielleicht kann man hier auf die Hilfe von uconv und co zurückgreifen, ich find die jedoch nicht wirklich intuitiv.

Daher lieber selbst die paar in Frage kommenden Zeichen rausfischen:

Code: Alles auswählen

sed 's_\(.\)_\1\n_g' datei.txt | grep -v "[a-z0-9A-Z,]" | sort -u
Das zerlegt die Datei erstmal Buchstabenweise, sammelt dann alle Zeilen raus die Buchstaben, Zahlen oder Komma enthalten, sortiert dann die übriggebliebenen Ergebnisse und gibt wegen -u davon jeweils nur eins aus (und ja, wahrscheinlich geht das schöner, z.B. indem man hier fürs Ersetzen nur sed nimmt - nur bekomm ich damit 'uniq' nicht so einfach hin ... na, Meillo?)

Alles was da übrigbleibt kann man dann in Ruhe in der Tabelle nachschlagen.

Oder es den Rechner machen lassen, ich bin dazu grad über Debianuni2ascii gestolpert, das hat nen paar interessante Optionen in der manpage, für den Fall hier scheint U passend:

Code: Alles auswählen

echo – | uni2ascii -a U -q
will man den uni2ascii Befehl direkt per Pipe an sed/sort anhängen, muss man wahrscheinlich auch noch bzgl. Encoding von Anführungszeichen und co aufpassen, daher hier alleinstehend, ging ja nur um nen paar Zeichen

guennid

Re: Zeichen ersetzen

Beitrag von guennid » 04.02.2019 19:25:10

Für mich ist das "technisch" nach wie vor nicht klar, denn das hier:

Code: Alles auswählen

sed "s_$'\u2013'_+_g; " test.txt
funktioniert nicht. In test.txt steht nichts außer:

Code: Alles auswählen

William C. „Billy“ Irvine sollen – und zwar
Die Behandlung der typografischen Anführungszeichen ist erledigt, darum geht's nicht (mehr). Das fragliche Zeichen, der "lange" Bindestrich wird nicht umgewandelt. Ich sehe im Moment nicht, dass ich in meinem Umsetzungsversuch irgendeine Anmerkung von eggy auf S.1 nicht beachtet hätte.

Und ich weiß nach wie vor nicht, ob es das an einem Syntaxfehler in eggys Vorschlag liegt, oder ob das von mir als "langer" Bindestrich genannte Zeichen eben nicht das von eggy vermutete utf-8-Zeichen ist.
Ersetze ich im sed Kommando eggys utf-8-Konstrukt ($'\u2013') via Tastatureingabe: AltGr+- dann wird das Zeichen umgewandelt.

Same procedure mit

Code: Alles auswählen

$ echo 'William C. „Billy“ Irvine sollen – und zwar' | sed "s_$'\u2013'_+_g; "
Zuletzt geändert von guennid am 04.02.2019 19:41:31, insgesamt 1-mal geändert.

Benutzeravatar
Meillo
Moderator
Beiträge: 8813
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Zeichen ersetzen

Beitrag von Meillo » 04.02.2019 19:41:14

guennid hat geschrieben: ↑ zum Beitrag ↑
04.02.2019 19:25:10
Für mich ist das "technisch" nach wie vor nicht klar, denn das hier:

Code: Alles auswählen

sed "s_$'\u2013'_+_g; " test.txt
funktioniert nicht.
Das kann auch nicht funktionieren. Es ist auch nicht das was eggy vorgeschlagen hat. ;-) Du musst genau (!) hinschauen! (Tipp: Quoting)
Use ed once in a while!

eggy
Beiträge: 3331
Registriert: 10.05.2008 11:23:50

Re: Zeichen ersetzen

Beitrag von eggy » 04.02.2019 19:42:00

Versuchs mal ohne die ". Hier müssen die ausnahmsweise mal weg, weil $'\u...' ja durch die Shell ersetzt werden soll.

Code: Alles auswählen

echo 'William C. „Billy“ Irvine sollen – und zwar' | sed s_$'\u2013'_+_g

guennid

Re: Zeichen ersetzen

Beitrag von guennid » 04.02.2019 19:45:43

ad Meillo
Und du solltest weniger selektiv lesen. :wink:

Bingo, Herr eggy!!! :THX: :mrgreen: :|

Antworten