Dans «sed», comment puis-je mettre un «&» entre les caractères d'une chaîne?


11

Peut sedfaire quelque chose comme:

12345

devenir :

1&2&3&4&5

?

Réponses:


25

Avec GNU sed:

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

( sremplacez chaque ( g) caractère ( .) par le même ( &) précédé de &( \&) mais uniquement à partir de la deuxième occurrence ( 2)).

Portablement:

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

(remplacez chaque occurrence, mais supprimez ensuite la première &dont nous ne voulons pas).

Avec certaines awkimplémentations (pas POSIX car le comportement n'est pas spécifié pour un FS vide):

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

(avec gawket quelques autres awkimplémentations, un séparateur de champ vide divise les enregistrements en ses composants de caractère . Le séparateur de champ de sortie ( OFS) est défini sur &. Nous attribuons une valeur à $1(lui-même) pour forcer la régénération de l'enregistrement avec le nouveau séparateur de champ avant de l'imprimer, NF=NFfonctionne également et est légèrement plus efficace dans de nombreuses implémentations awk mais le comportement lorsque vous le faites n'est actuellement pas spécifié par POSIX).

perl:

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

( -peexécute le code pour chaque ligne et imprime le résultat ( $_); -lsupprime et rajoute automatiquement les fins de ligne; se -aremplit @Favec le fractionnement d'entrée sur le délimiteur défini dans -F, qui est ici une chaîne vide. Le résultat est de diviser chaque caractère en @F, puis joignez-les avec «&» et imprimez la ligne.)

Alternativement:

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

(remplacez chaque caractère à condition qu'il soit précédé d'un autre caractère (opérateur d'expression rationnelle en arrière-plan (? <= ...))

Utilisation zshdes opérateurs shell:

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

(encore une fois, divisez sur un séparateur de champ vide à l'aide de l' s::indicateur d'extension de paramètre et joignez-le &)

Ou:

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

(remplacez chaque occurrence de rien (donc avant chaque caractère) par l' &utilisation de l' ${var//pattern/replacement}opérateur ksh (bien que dans kshun modèle vide signifie quelque chose d'autre, et pourtant quelque chose d'autre, je ne sais pas quoi bash), et supprimez la première avec le ${var#pattern}décapage POSIX opérateur).

Utilisation ksh93des opérateurs shell:

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

( ~(P:perl-like-RE)étant un opérateur glob ksh93 pour utiliser des expressions régulières de type perl (différent de perl ou PCRE), (?=.)étant l' opérateur d'anticipation : remplacez un caractère à condition qu'il soit suivi d'un autre caractère avec lui-même ( \0) et &)

Ou:

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

(remplacez chaque caractère ( ?) par &et lui-même ( \0), et nous supprimons le superflous)

Utilisation bashdes opérateurs shell:

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

(identique à celui zshde, sauf que vous en avez besoin @()(un opérateur ksh glob pour lequel vous extgloben avez besoin bash)).


2
@AFSHIN, ça ne marcherait pas sur une 012345entrée
Stéphane Chazelas

1
cela devrait fonctionnerawk -F '' -v OFS="&" 'NF=NF'
αғsнιη

1
@AFSHIN, mais supprimez les lignes vides. Plus généralement, lorsque vous utilisez une action comme condition et que le résultat de l'action est imprimé, vous devez vous assurer que la valeur renvoyée par l'action n'est pas une chaîne vide ou une chaîne numérique qui se résout à 0.
Stéphane Chazelas

1
Pourriez-vous ajouter une explication rapide de la façon dont chacun de ces éléments fonctionne? Il semble qu'il y ait des choses impressionnantes à apprendre ici, mais je ne sais même pas par où commencer la recherche pour la plupart pour voir comment les appliquer en dehors de la portée de ce problème spécifique.
IMSoP

1
@ StéphaneChazelas Brillant, merci. La recherche de documents complexes pour des choses comme sed est un peu un art, donc avoir des exemples pratiques est un excellent moyen d'apprendre de nouveaux bits que vous n'aviez jamais vus auparavant.
IMSoP

15

Utilitaires Unix:

fold -w1|paste -sd\& -

Expliqué:

"fold -w1" - encapsulera chaque caractère saisi sur sa propre ligne

plier - envelopper chaque ligne d'entrée pour s'adapter à la largeur spécifiée

-w, --width = WIDTH utilise des colonnes WIDTH au lieu de 80

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

"paste -sd\& -"- fusionnera les lignes d'entrée ensemble, en utilisant &comme séparateur

coller - fusionner des lignes de fichiers

-s, --serial coller un fichier à la fois plutôt qu'en parallèle

-d, --delimiters = LIST réutilise les caractères de LIST au lieu de TABs

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

(Notez que si l'entrée contient plusieurs lignes, elles seront jointes avec &)


2
Échec sur les caractères multi-octets. Essayezecho "abcdeéèfg" | fold -1 | paste -sd\& -
Isaac

3
@Arrow Vous utilisez probablement une version buggy coreutils de fold , qui ne prend pas en charge Unicode. Le pliage BSD, les versions corrigées de RedHat de coreutils (c'est-à-dire Fedora ou CentOS) ainsi que l'implémentation de BusyBox, peuvent gérer Unicode tout simplement bien.
zeppelin

5
La question porte précisément sur sed.
Alexander

6
@Alexander - c'est vrai, et il y a un certain nombre de bonnes sedréponses disponibles ci-dessous. Et je ne vois aucun mal à démontrer comment la tâche peut être résolue par les autres moyens.
zeppelin

@ StéphaneChazelas> POSIX, vous auriez besoin de fold -w 1 Vrai, j'ai ajouté "-w", merci! "-", à son tour, n'est pas nécessaire If no file operands are specified, the standard input shall be used
zeppelin


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

\ B - Correspond partout mais sur une limite de mot; c'est-à-dire qu'il correspond si le caractère à gauche et le caractère à droite sont tous les deux des caractères «mot» ou des caractères «non-mot».

Informations: manuel GNU sed, extensions d'expressions régulières .

Essai:

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

5
Idée intéressante mais la question ne dit pas que la chaîne ne contient pas d'espace, de point ou quoi que ce soit qui pourrait constituer une limite de mot. Il dit simplement "entre les caractères" qui doit être interprété comme "n'importe quel caractère".
xhienne

4

Ce sera un peu plus lent que certaines des autres réponses, mais c'est assez clair:

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

4

Voici une autre façon. La première partie de l'expression sed capture chaque personnage, puis la remplace par le personnage et une esperluette. La deuxième partie supprime l'esperluette de la fin de la ligne.

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

Fonctionne également sur les caractères multi-octets.


1
Pas besoin d'appeler seddeux fois, un sedscript peut avoir plusieurs commandes:sed -r 's/(.)/\1\&/g; s/\&$//g'
xhienne

xhienne, merci, TIL! Mis à jour la réponse.
Alexander
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.