2011-12-19 27 views
18

Lo creas o no, no puedo encontrar la respuesta a lo que creo que sería esta pregunta muy básica.bucle sobre los caracteres en la cadena de entrada utilizando awk

En awk, ¿cómo puedo recorrer la cadena de entrada carácter por carácter? Digamos que solo quería imprimirlos. ¿Hay una matriz a la que pueda acceder? ¿O necesito usar substr?

Básicamente, algo así como:

echo "here is a string" | awk ' 
{ for(i=0; i<[length of input string]; i++) 
    printf [value at index i in array x]; 
}' 

Francamente, me da vergüenza.

Respuesta

32

Puede convertir una cadena en una matriz mediante split:

echo "here is a string" | awk ' 
{ 
    split($0, chars, "") 
    for (i=1; i <= length($0); i++) { 
    printf("%s\n", chars[i]) 
    } 
}' 

Esto imprime los caracteres verticalmente, uno por línea.

+0

en realidad, length() es una extensión de gawk AFAIK, no funciona en awk puro http://stackoverflow.com/questions/14720898/illegal-reference-to-an-array-in-awk-i- Tengo-problema-descifrar-awk – vaxquis

+0

@vaxquis No estoy seguro de lo que quiere decir con "puro" awk, pero 'length' está en POSIX. La extensión gawk se aplica a matrices en lugar de cadenas. Afortunadamente, podemos simplemente cambiar 'length (chars)' a 'length ($ 0)'. –

+2

awk "puro" en el sentido de "no awk extendido" ... y sí, quise decir este uso de length(); también puede usar "len = split (...)" y luego "i <= len" con el mismo resultado. – vaxquis

0

si tiene gawk:

awk '$0=gensub(/(.)/,"\\1\n","g")' file 

prueba:

kent$ echo "I am a String"|awk '$0=gensub(/(.)/,"\\1\n","g")' 
I 

a 
m 

a 

S 
t 
r 
i 
n 
g 
+0

¿Hay alguna manera de hacer algo con cada personaje usando este método o solo se está reformateando la cadena? –

+1

puede "hacer algo con cada char". pero depende de qué es "algo" – Kent

13

Por defecto en el awkField Separator (FS) es space o tabs. Como mencionaste que querías repetir cada carácter y no la palabra, tendremos que redefinir el FS a nada. Algo como esto:

[jaypal:~/Temp] echo "here is a string" | awk -v FS="" ' 
{for (i=1;i<=NF;i++) printf "Character "i": " $i"\n"}' 
Character 1: h 
Character 2: e 
Character 3: r 
Character 4: e 
Character 5: 
Character 6: i 
Character 7: s 
Character 8: 
Character 9: a 
Character 10: 
Character 11: s 
Character 12: t 
Character 13: r 
Character 14: i 
Character 15: n 
Character 16: g 
+0

AFAIK puede establecer FS = "" en el código, no es necesario usarlo fuera de él ... – vaxquis

+0

hm. de hecho, funciona cuando FS se establece en el código, pero de una manera un poco diferente ... (por ejemplo, la primera línea no se analiza) ¿Alguna idea de por qué? – vaxquis

+2

Es porque la primera línea ya se ha leído antes con FS por defecto. –

5

No todas las implementaciones de awk admiten las soluciones anteriores. En ese caso se podría utilizar substr :

echo here is a string | awk '{ 
    for (i=0; ++i <= length($0);) 
    printf "%s\n", substr($0, i, 1) 
    }' 

P. S. En algunos AWK implementaciones de longitud sin argumentos valores predeterminados para $ 0, es decir longitud y longitud ($ 0) son equivalentes.

Cuestiones relacionadas