Wie kann ich in `sed` ein" & "zwischen Zeichen in einer Zeichenfolge setzen?

11

Kann sedso etwas machen wie:

12345

werden:

1&2&3&4&5

?

GAD3R
quelle

Antworten:

25

Mit GNU sed:

sed 's/./\&&/2g'

( sErsetzen Sie jedes ( g) Zeichen ( .) durch dasselbe ()& ) vor &( \&), jedoch erst ab dem zweiten Vorkommen ( 2)).

Tragbar:

sed 's/./\&&/g;s/&//'

(Ersetzen Sie jedes Vorkommen, aber entfernen Sie dann das erste, &das wir nicht wollen).

Bei einigen awkImplementierungen (nicht POSIX, da das Verhalten für einen leeren FS nicht angegeben ist):

awk -F '' -v OFS="&" '{$1=$1;print}'

(Mit gawkund einigen anderen awkImplementierungen teilt ein leeres Feldtrennzeichen die Datensätze in ihre Zeichenbestandteile auf . Das Ausgabefeldtrennzeichen ( OFS) ist auf gesetzt &. Wir weisen einen Wert zu$1 (selbst) zu erzwingen, dass der Datensatz mit dem neuen Feldtrennzeichen neu generiert wird vor dem Drucken NF=NFfunktioniert auch und ist in vielen awk-Implementierungen etwas effizienter, aber das Verhalten, wenn Sie dies tun, ist derzeit von POSIX nicht spezifiziert.

perl::

perl -F -lape '$_=join"&",@F' 

( -peführt den Code für jede Zeile aus und druckt das Ergebnis aus ( $_); entfernt -lund fügt Zeilenenden automatisch wieder hinzu; -afüllt die @FEingabe mit dem eingegebenen Trennzeichen -F, das hier eine leere Zeichenfolge ist. Das Ergebnis besteht darin, jedes Zeichen in zu teilen@F : Verbinden Sie sie dann mit '&' und drucken Sie die Zeile aus.)

Alternative:

perl -pe 's/(?<=.)./&$&/g' 

(Ersetzen Sie jedes Zeichen, sofern ihm ein anderes Zeichen vorangestellt ist (Rückblick-Regexp-Operator (? <= ...)).

Verwenden von zshShell-Operatoren:

in=12345
out=${(j:&:)${(s::)in}}

(Teilen Sie erneut ein leeres Feldtrennzeichen mit dem s::Parameter-Erweiterungsflag auf und verbinden Sie sich mit& )

Oder:

out=${in///&} out=${out#?}

(Ersetzen Sie jedes Vorkommen von nichts (also vor jedem Zeichen) durch die &Verwendung des ${var//pattern/replacement}ksh-Operators (obwohl kshein leeres Muster etwas anderes bedeutet, und noch etwas anderes, ich bin mir nicht sicher, was drin ist bash), und entfernen Sie das erste mit dem POSIX- ${var#pattern}Stripping Operator).

Verwenden von ksh93Shell-Operatoren:

in=12345
out=${in//~(P:.(?=.))/\0&}

(Als ~(P:perl-like-RE)ksh93-Glob-Operator, der perlähnliche reguläre Ausdrücke verwendet (allerdings anders als bei Perls oder PCREs), (?=.)als Look-Ahead-Operator: Ersetzen Sie ein Zeichen, sofern ihm ein anderes Zeichen folgt, durch sich selbst ( \0) und &)

Oder:

out=${in//?/&\0}; out=${out#?}

(Ersetzen Sie jedes Zeichen ( ?) durch &und sich selbst ( \0), und wir entfernen das überflüssige)

Verwenden von bashShell-Operatoren:

shopt -s extglob
in=12345
out=${in//@()/&}; out=${out#?}

( das gleiche wie zsh‚s, mit der Ausnahme , dass Sie braucht @()es (a KSH glob Operator für die Sie brauchen extglobin bash)).

Stéphane Chazelas
quelle
2
@ AFSHIN, das würde bei einer 012345Eingabe nicht funktionieren
Stéphane Chazelas
1
Dies sollte funktionierenawk -F '' -v OFS="&" 'NF=NF'
αғsнιη
1
@AFSHIN, aber leere Zeilen entfernen. Wenn Sie eine Aktion als Bedingung verwenden und das Ergebnis der zu druckenden Aktion beabsichtigen, müssen Sie im Allgemeinen sicherstellen, dass der von der Aktion zurückgegebene Wert keine leere Zeichenfolge oder eine numerische Zeichenfolge ist, die in 0 aufgelöst wird.
Stéphane Chazelas
1
Können Sie kurz erläutern, wie diese Funktionen funktionieren? Es sieht so aus, als gäbe es hier einige großartige Dinge zu lernen, aber ich weiß nicht einmal, wo ich anfangen würde, die meisten von ihnen zu untersuchen, um herauszufinden, wie man sie außerhalb des Rahmens dieses spezifischen Problems anwendet.
IMSoP
1
@ StéphaneChazelas Genial, danke. Das Durchsuchen komplexer Dokumente nach Dingen wie sed ist eine Kunst, daher ist es eine großartige Möglichkeit, neue Beispiele zu lernen, die Sie zuvor noch nicht gesehen haben.
IMSoP
15

Unix-Dienstprogramme:

fold -w1|paste -sd\& -

Erklärt:

"fold -w1" - umschließt jedes eingegebene Zeichen mit einer eigenen Zeile

Falten - Wickeln Sie jede Eingabezeile so, dass sie in die angegebene Breite passt

-w, --width = WIDTH Verwenden Sie WIDTH-Spalten anstelle von 80

%echo 12345|fold -w1
1
2
3
4
5

"paste -sd\& -"- führt die Eingabezeilen zusammen und verwendet sie &als Trennzeichen

Einfügen - Zeilen von Dateien zusammenführen

-s, --serial Einfügen einer Datei nach der anderen anstatt parallel

-d, --delimiters = LIST verwendet Zeichen aus LIST anstelle von TABs wieder

%fold -w1|paste -sd\& -
1&2&3&4&5

(Beachten Sie, dass wenn die Eingabe mehrere Zeilen enthält, diese mit verbunden werden. &)

Zeppelin
quelle
2
Fehler bei Multibyte-Zeichen. Versuchen Sieecho "abcdeéèfg" | fold -1 | paste -sd\& -
Pfeil
3
@Arrow Wahrscheinlich Sie verwenden nur einen Buggy coreutils Version von Falte , die keine volle Unicode - Unterstützung bietet. BSD-Fold, RedHat-gepatchte Versionen von Coreutils (dh Fedora oder CentOS) sowie die BusyBox-Implementierung können mit Unicode einfach gut umgehen.
Zeppelin
5
Die Frage ist speziell über sed.
Alexander
6
@Alexander - das ist wahr, und es gibt eine Reihe guter sedAntworten unten. Und ich sehe keinen Schaden darin, zu demonstrieren, wie die Aufgabe auf andere Weise gelöst werden kann.
Zeppelin
@ StéphaneChazelas> POSIXly, du brauchst Fold -w 1 Stimmt, ich habe hinzugefügt "-w", danke! "-"wiederum ist nicht erforderlich If no file operands are specified, the standard input shall be used
Zeppelin
11

Verwenden sed

sed 's/./&\&/g;s/.$//'
αғsнιη
quelle
9
sed 's/\B/\&/g'

\ B - Stimmt überall überein, außer an einer Wortgrenze. Das heißt, es stimmt überein, wenn das Zeichen links und das Zeichen rechts entweder beide "Wort" -Zeichen oder beide "Nicht-Wort" -Zeichen sind.

Information: GNU sed Handbuch, reguläre Ausdruckserweiterungen .

Testen:

sed 's/\B/\&/g' <<< '12345'
1&2&3&4&5
MiniMax
quelle
5
Interessante Idee, aber die Frage besagt nicht, dass die Zeichenfolge kein Leerzeichen, keinen Punkt oder irgendetwas enthält, das eine Wortgrenze bilden könnte. Es steht nur "zwischen Zeichen", was als "beliebige Zeichen" interpretiert werden sollte.
Xhienne
4

Dies wird etwas langsamer sein als einige der anderen Antworten, aber es ist ziemlich klar:

echo 12345 | perl -lnE 'say join "&", split //'
Glenn Jackman
quelle
4

Hier ist ein anderer Weg. Der erste Teil des sed-Ausdrucks erfasst jedes Zeichen und ersetzt dieses durch das Zeichen und ein kaufmännisches Und. Der zweite Teil entfernt das kaufmännische Und vom Zeilenende.

echo 12345 | sed -r 's/(.)/\1\&/g;s/\&$//g'
1&2&3&4&5

Funktioniert auch mit Multibyte-Zeichen.

Alexander
quelle
1
Sie müssen nicht sedzweimal aufrufen , ein sedSkript kann mehrere Befehle enthalten:sed -r 's/(.)/\1\&/g; s/\&$//g'
xhienne
xhienne, danke, bis! Die Antwort wurde aktualisiert.
Alexander