En `sed`, ¿cómo puedo poner un" & "entre caracteres en una cadena?


Respuestas:


25

Con GNU sed:

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

( ssustituya cada gcarácter ( .) con ( &) precedido por &( \&) pero solo a partir de la segunda aparición ( 2)).

Portablemente:

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

(reemplaza cada aparición, pero luego elimina la primera &que no queremos).

Con algunas awkimplementaciones (no POSIX ya que el comportamiento no está especificado para un FS vacío):

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

(con gawky algunas otras awkimplementaciones, un separador de campo vacío divide los registros en sus componentes de caracteres . El separador de campo de salida ( OFS) se establece en &. Asignamos un valor a $1(sí mismo) para forzar la regeneración del registro con el nuevo separador de campo antes de imprimirlo, NF=NFtambién funciona y es un poco más eficiente en muchas implementaciones awk, pero el comportamiento cuando lo hace no está especificado por POSIX).

perl:

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

( -peEjecuta el código para cada línea, e imprime el resultado ( $_); -ltiras y vuelve a agregar los finales de línea de forma automática; -apuebla @Fcon fractura de entrada en el set delimitador en -F., Que aquí es una cadena vacía El resultado es dividir cada carácter en @F, luego únalas con '&' e imprima la línea).

Alternativamente:

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

(reemplace cada carácter siempre que esté precedido por otro carácter (operador regexp retrospectivo (? <= ...))

Usar zshoperadores de shell:

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

(de nuevo, divida en un separador de campo vacío con el s::indicador de expansión de parámetros y únase a &)

O:

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

(reemplace cada aparición de nada (por lo tanto, antes de cada carácter) con el &uso del ${var//pattern/replacement}operador ksh (aunque en kshun patrón vacío significa algo más y, sin embargo, algo más, no estoy seguro de qué bash), y elimine el primero con el ${var#pattern}pelado POSIX operador).

Usar ksh93operadores de shell:

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

( ~(P:perl-like-RE)siendo un operador global de ksh93 para usar expresiones regulares similares a Perl (diferentes de las de Perl o PCRE), (?=.)siendo el operador de búsqueda anticipada: reemplace un carácter siempre que sea seguido por otro carácter consigo mismo ( \0) y &)

O:

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

(reemplaza cada carácter ( ?) con &y en sí mismo ( \0), y eliminamos el superflous)

Usar bashoperadores de shell:

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

(igual que zsh's, salvo que se debe @()allí (un operador de ksh pegote para el que necesita extgloben bash)).


2
@AFSHIN, eso no funcionaría en una 012345entrada
Stéphane Chazelas

1
esto debería funcionarawk -F '' -v OFS="&" 'NF=NF'
αғsнιη

1
@AFSHIN, pero elimine las líneas vacías. En términos más generales, cuando se utiliza una acción como condición y se pretende que se imprima el resultado de la acción, debe asegurarse de que el valor devuelto por la acción no sea una cadena vacía o una cadena numérica que se resuelva en 0.
Stéphane Chazelas

1
¿Podría agregar una explicación rápida de cómo funciona cada uno de estos? Parece que hay algunas cosas increíbles que aprender aquí, pero ni siquiera sé dónde comenzaría a investigar la mayoría de ellas para ver cómo aplicarlas fuera del alcance de este problema específico.
IMSoP

1
@ StéphaneChazelas Brillante, gracias. Buscar documentos complejos para cosas como sed es un poco un arte, por lo que tener algunos ejemplos prácticos es una excelente manera de aprender nuevos bits que no había visto antes.
IMSoP

15

Utilidades Unix:

fold -w1|paste -sd\& -

Explicado:

"fold -w1" - envolverá cada carácter de entrada en su propia línea

doblar: ajusta cada línea de entrada para que se ajuste al ancho especificado

-w, --width = WIDTH usa columnas WIDTH en lugar de 80

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

"paste -sd\& -"- fusionará las líneas de entrada juntas, utilizándolas &como separador

pegar: fusionar líneas de archivos

-s, --serial pegar un archivo a la vez en lugar de en paralelo

-d, --delimiters = LIST reutiliza caracteres de LIST en lugar de TAB

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

(Tenga en cuenta que si la entrada contiene varias líneas, se unirán con &)


2
Falla en caracteres multibyte. Pruebaecho "abcdeéèfg" | fold -1 | paste -sd\& -
Isaac

3
@Arrow Lo más probable es que solo estés usando una versión de coreutils con errores de fold , que no tiene un soporte completo de Unicode. BSD Fold, las versiones de Coreutils parcheadas con RedHat (es decir, Fedora o CentOS), así como la implementación de BusyBox, pueden manejar Unicode simplemente bien.
zepelín

55
La pregunta es específicamente sobre sed.
Alexander

66
@Alexander: eso es cierto, y hay una serie de buenas sedrespuestas disponibles a continuación. Y no veo ningún daño en demostrar cómo se puede resolver la tarea por otros medios.
zepelín

@ StéphaneChazelas> POSIXY, necesitarías doblar -w 1 Verdadero, he agregado "-w", ¡gracias! "-", a su vez, no es obligatorio If no file operands are specified, the standard input shall be used
zepelín


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

\ B - Coincide en todas partes excepto en un límite de palabra; es decir, coincide si el carácter a la izquierda y el carácter a la derecha son caracteres de "palabra" o caracteres de "no palabra".

Información: GNU sed manual, extensiones de expresión regular .

Pruebas:

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

55
Idea interesante, pero la pregunta no dice que la cadena no contiene un espacio, un punto o cualquier cosa que pueda constituir un límite de palabra. Simplemente dice "entre caracteres", que debe interpretarse como "cualquier carácter".
xhienne

4

Esto será un poco más lento que algunas de las otras respuestas, pero está bastante claro:

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

4

Aquí hay otra forma. La primera parte de la expresión sed captura a cada personaje y luego la reemplaza con el personaje y un signo. La segunda parte elimina el ampersand del final de la línea.

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

Funciona también en caracteres multibyte.


1
No es necesario llamar seddos veces, un sedscript puede tener varios comandos:sed -r 's/(.)/\1\&/g; s/\&$//g'
xhienne

xhienne, gracias, TIL! Se actualizó la respuesta.
Alexander
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.