In `sed` come posso mettere un“ & ”tra i caratteri in una stringa?


11

Può sedfare qualcosa del tipo:

12345

diventare:

1&2&3&4&5

?

Risposte:


25

Con GNU sed:

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

( substitute ogni ( g) carattere ( .) con lo stesso ( &) preceduto da &( \&) ma a partire solo dalla seconda occorrenza ( 2)).

portabile:

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

(sostituisci ogni ricorrenza, ma poi rimuovi il primo &che non vogliamo).

Con alcune awkimplementazioni (non POSIX in quanto il comportamento non è specificato per un FS vuoto):

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

(con gawke alcune altre awkimplementazioni, un separatore di campo vuoto divide i record nei suoi componenti di carattere . Il separatore di campo di output ( OFS) è impostato su &. Assegniamo un valore a $1(stesso) per forzare la rigenerazione del record con il nuovo separatore di campo prima di stamparlo, NF=NFfunziona anche ed è leggermente più efficiente in molte implementazioni awk ma il comportamento quando lo fai è attualmente non specificato da POSIX).

perl:

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

( -peesegue il codice per ogni riga e stampa il risultato ( $_); -lelimina e aggiunge nuovamente le terminazioni di riga automaticamente; -apopola @Fcon suddivisione in input sul delimitatore impostato -F, che qui è una stringa vuota. Il risultato è di dividere ogni carattere in @F, quindi uniscili con '&' e stampa la riga.)

In alternativa:

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

(sostituisci ogni carattere a condizione che sia preceduto da un altro personaggio (operatore regexp look-behind (? <= ...))

Utilizzo degli zshoperatori shell:

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

(di nuovo, dividi su un separatore di campo vuoto usando il s::flag di espansione dei parametri e unisciti a &)

O:

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

(sostituisci ogni ricorrenza di nulla (quindi prima di ogni carattere) con l' &uso ${var//pattern/replacement}dell'operatore ksh (anche se in kshun modello vuoto significa qualcos'altro, eppure qualcos'altro, non sono sicuro di cosa ci sia dentro bash), e rimuovi il primo con lo ${var#pattern}stripping POSIX operatore).

Utilizzo degli ksh93operatori shell:

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

( ~(P:perl-like-RE)essendo un operatore glob ksh93 per usare espressioni regolari tipo perl (diverso da perl o PCRE), (?=.)essendo l'operatore look-ahead: sostituisci un personaggio a condizione che sia seguito da un altro personaggio con se stesso ( \0) e &)

O:

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

(sostituiamo ogni carattere ( ?) con &e se stesso ( \0) e rimuoviamo quello superflous)

Utilizzo degli bashoperatori shell:

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

(lo stesso di zsh's, tranne che avete bisogno di @()lì (un operatore di ksh glob per il quale è necessario extglobin bash)).


2
@AFSHIN, che non funzionerebbe su un 012345input
Stéphane Chazelas,

1
questo dovrebbe funzionareawk -F '' -v OFS="&" 'NF=NF'
αғsнιη il

1
@AFSHIN, ma rimuovi le righe vuote. Più in generale, quando si utilizza un'azione come condizione e si intende il risultato dell'azione da stampare, è necessario assicurarsi che il valore restituito dall'azione non sia una stringa vuota o una stringa numerica che si risolve in 0.
Stéphane Chazelas

1
Potresti aggiungere una breve spiegazione di come funzionano questi? Sembra che ci siano alcune cose fantastiche da imparare qui, ma non so nemmeno da dove inizierei a ricercare la maggior parte di esse per vedere come applicarle al di fuori di questo specifico problema.
IMSoP,

1
@ StéphaneChazelas Brilliant, grazie. La ricerca di documenti complessi per cose come sed è un po 'un'arte, quindi avere alcuni esempi pratici è un ottimo modo per imparare nuovi bit che non avevi mai visto prima.
IMSoP,

15

Utilità Unix:

fold -w1|paste -sd\& -

Ha spiegato:

"fold -w1" - avvolgerà un carattere di ogni input nella sua riga

piega: avvolge ciascuna riga di input per adattarla alla larghezza specificata

-w, --width = WIDTH usa le colonne WIDTH anziché 80

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

"paste -sd\& -"- Unirà le linee di input insieme, usando &come separatore

incolla: unisce le righe dei file

-s, --serial incolla un file alla volta anziché in parallelo

-d, --delimiters = LIST riutilizza i caratteri da LIST anziché dai TAB

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

(Nota che se l'input contiene più righe, verranno unite &)


2
Errore sui caratteri multibyte. Provaecho "abcdeéèfg" | fold -1 | paste -sd\& -
Isaac,

3
@Arrow Molto probabilmente stai usando una versione di fold di coreutils con buggy , che non ha un supporto Unicode completo. BSD fold, le versioni di coreutils (cioè Fedora o CentOS) con patch RedHat e l'implementazione di BusyBox, possono gestire Unicode semplicemente bene.
Zeppelin,

5
La domanda riguarda in particolare sed.
Alexander,

6
@Alexander - questo è vero, e ci sono un numero di buone sedrisposte disponibili di seguito. E non vedo alcun danno nel dimostrare come il compito può essere risolto con gli altri mezzi.
Zeppelin,

@ StéphaneChazelas> POSIX, avresti bisogno di fold -w 1 Vero, ho aggiunto "-w", grazie! "-", a sua volta, non è richiesto If no file operands are specified, the standard input shall be used
zeppelin il


9
sed 's/\B/\&/g'

\ B - Corrisponde ovunque ma su un limite di parole; vale a dire se il carattere a sinistra e il carattere a destra sono entrambi caratteri "parola" o entrambi caratteri "non parola".

Informazioni: manuale GNU sed, estensioni di espressioni regolari .

test:

sed 's/\B/\&/g' <<< '12345'
1&2&3&4&5

5
Idea interessante ma la domanda non dice che la stringa non contenga uno spazio, un punto o qualsiasi cosa che possa costituire un confine di parola. Dice solo "tra i personaggi" che dovrebbe essere interpretato come "qualsiasi personaggio".
Xhienne,

4

Questo sarà un po 'più lento di alcune delle altre risposte, ma è abbastanza chiaro:

echo 12345 | perl -lnE 'say join "&", split //'

4

Ecco un altro modo. La prima parte dell'espressione sed cattura ogni personaggio, poi lo sostituisce con il personaggio e una e commerciale. La seconda parte rimuove la e commerciale dalla fine della linea.

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

Funziona anche su caratteri multibyte.


1
Non è necessario chiamare seddue volte, uno sedscript può avere diversi comandi:sed -r 's/(.)/\1\&/g; s/\&$//g'
xhienne

xhienne, grazie, TIL! Aggiornato la risposta.
Alexander,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.