regular pattern online regex sed

regex - pattern - ¿Cómo dar salida solo a los grupos capturados con sed?



sed replace string (8)

¿Hay alguna manera de decirle a sed que muestre solo los grupos capturados? Por ejemplo, dada la entrada:

This is a sample 123 text and some 987 numbers

y patrón:

/([/d]+)/

¿Puedo obtener solo 123 y 987 salidas en la forma formateada por referencias anteriores?


ejecución (es) de dígitos

Esta respuesta funciona con cualquier cuenta de grupos de dígitos. Ejemplo:

$ echo ''Num123that456are7899900contained0018166intext'' | > sed -En ''s/[^0-9]*([0-9]{1,})[^0-9]*//1 /gp'' 123 456 7899900 0018166

Respuesta ampliada.

¿Hay alguna manera de decirle a sed que muestre solo los grupos capturados?

Sí. Reemplace todo el texto por el grupo de captura:

$ echo ''Number 123 inside text'' | sed ''s/[^0-9]*/([0-9]/{1,/}/)[^0-9]*//1/'' 123 s/[^0-9]* # several non-digits /([0-9]/{1,/}/) # followed by one or more digits [^0-9]* # and followed by more non-digits. //1/ # gets replaced only by the digits.

O con sintaxis extendida (menos backquotes y permite el uso de +):

$ echo ''Number 123 in text'' | sed -E ''s/[^0-9]*([0-9]+)[^0-9]*//1/'' 123

Para evitar imprimir el texto original cuando no hay un número, use:

$ echo ''Number xxx in text'' | sed -En ''s/[^0-9]*([0-9]+)[^0-9]*//1/p''

  • (-n) No imprime la entrada por defecto.
  • (/ p) imprimir solo si se realizó un reemplazo.

Y para hacer coincidir varios números (y también imprimirlos):

$ echo ''N 123 in 456 text'' | sed -En ''s/[^0-9]*([0-9]+)[^0-9]*//1 /gp'' 123 456

Eso funciona para cualquier cuenta de carreras de dígitos:

$ str=''Test Num(s) 123 456 7899900 contained as0018166df in text'' $ echo "$str" | sed -En ''s/[^0-9]*([0-9]{1,})[^0-9]*//1 /gp'' 123 456 7899900 0018166

Que es muy similar al comando grep:

$ str=''Test Num(s) 123 456 7899900 contained as0018166df in text'' $ echo "$str" | grep -Po ''/d+'' 123 456 7899900 0018166

Acerca de / d

y patrón: /([/d]+)/

Sed no reconoce la sintaxis ''/ d'' (acceso directo). El equivalente de ascii usado arriba [0-9] no es exactamente equivalente. La única solución alternativa es usar una clase de caracteres: ''[[: digit:]] `.

La respuesta seleccionada usa tales "clases de caracteres" para construir una solución:

$ str=''This is a sample 123 text and some 987 numbers'' $ echo "$str" | sed -rn ''s/[^[:digit:]]*([[:digit:]]+)[^[:digit:]]+([[:digit:]]+)[^[:digit:]]*//1 /2/p''

Esa solución solo funciona para (exactamente) dos series de dígitos.

Por supuesto, como la respuesta se está ejecutando dentro del shell, podemos definir un par de variables para acortar la respuesta:

$ str=''This is a sample 123 text and some 987 numbers'' $ d=[[:digit:]] D=[^[:digit:]] $ echo "$str" | sed -rn "s/$D*($d+)$D+($d+)$D*//1 /2/p"

Pero, como ya se ha explicado, es mejor usar el comando s/…/…/gp :

$ str=''This is 75577 a sam33ple 123 text and some 987 numbers'' $ d=[[:digit:]] D=[^[:digit:]] $ echo "$str" | sed -rn "s/$D*($d+)$D*//1 /gp" 75577 33 123 987

Eso cubrirá tanto la repetición de dígitos como la escritura de un comando corto (er).


Creo que el patrón dado en la pregunta fue solo a modo de ejemplo, y el objetivo era igualar cualquier patrón.

Si tiene un sed con la extensión GNU que permite la inserción de una nueva línea en el espacio del patrón, una sugerencia es:

> set string = "This is a sample 123 text and some 987 numbers" > > set pattern = "[0-9][0-9]*" > echo $string | sed "s/$pattern//n&/n/g" | sed -n "/$pattern/p" 123 987 > set pattern = "[a-z][a-z]*" > echo $string | sed "s/$pattern//n&/n/g" | sed -n "/$pattern/p" his is a sample text and some numbers

Estos ejemplos están con tcsh (sí, sé que es la cáscara incorrecta) con CYGWIN. (Editar: para bash, eliminar set, y los espacios alrededor de =.)


La clave para que esto funcione es decirle a sed que excluya lo que no desea que se genere, así como que especifique lo que quiere.

string=''This is a sample 123 text and some 987 numbers'' echo "$string" | sed -rn ''s/[^[:digit:]]*([[:digit:]]+)[^[:digit:]]+([[:digit:]]+)[^[:digit:]]*//1 /2/p''

Esto dice:

  • no predeterminado para imprimir cada línea ( -n )
  • excluir cero o más no dígitos
  • incluir uno o más dígitos
  • excluir uno o más no dígitos
  • incluir uno o más dígitos
  • excluir cero o más no dígitos
  • imprimir la sustitución ( p )

En general, en sed se capturan grupos utilizando paréntesis y se obtiene lo que se captura utilizando una referencia posterior:

echo "foobarbaz" | sed ''s/^foo/(.*/)baz$//1/''

Saldrá "bar". Si usa -r ( -E para OS X) para expresiones regulares extendidas, no necesita escapar de los paréntesis:

echo "foobarbaz" | sed -r ''s/^foo(.*)baz$//1/''

Puede haber hasta 9 grupos de captura y sus referencias anteriores. Las referencias anteriores están numeradas en el orden en que aparecen los grupos, pero se pueden usar en cualquier orden y se pueden repetir:

echo "foobarbaz" | sed -r ''s/^foo(.*)b(.)z$//2 /1 /2/''

da salida a "una barra a".

Si tiene GNU grep (también puede funcionar en BSD, incluido OS X):

echo "$string" | grep -Po ''/d+''

o variaciones tales como:

echo "$string" | grep -Po ''(?<=/D )(/d+)''

La opción -P habilita expresiones regulares compatibles con Perl. Ver man 3 pcrepattern o man 3 pcresyntax .


No es lo que pidió el OP (capturar grupos) pero puede extraer los números usando:

S=''This is a sample 123 text and some 987 numbers'' echo "$S" | sed ''s/ //n/g'' | sed -r ''/([0-9]+)/ !d''

Da lo siguiente:

123 987


Sed tiene hasta nueve patrones recordados, pero necesitas usar paréntesis escapados para recordar partes de la expresión regular.

Vea here para ejemplos y más detalles


Tratar

sed -n -e "/[0-9]/s/^[^0-9]*/([0-9]*/)[^0-9]*/([0-9]*/)[^0-9]*/([0-9]*/)[^0-9]*/([0-9]*/)[^0-9]*/([0-9]*/)[^0-9]*/([0-9]*/)[^0-9]*/([0-9]*/)[^0-9]*/([0-9]*/)[^0-9]*/([0-9]*/).*$//1 /2 /3 /4 /5 /6 /7 /8 /9/p"

Tengo esto bajo cygwin:

$ (echo "asdf"; / echo "1234"; / echo "asdf1234adsf1234asdf"; / echo "1m2m3m4m5m6m7m8m9m0m1m2m3m4m5m6m7m8m9") | / sed -n -e "/[0-9]/s/^[^0-9]*/([0-9]*/)[^0-9]*/([0-9]*/)[^0-9]*/([0-9]*/)[^0-9]*/([0-9]*/)[^0-9]*/([0-9]*/)[^0-9]*/([0-9]*/)[^0-9]*/([0-9]*/)[^0-9]*/([0-9]*/)[^0-9]*/([0-9]*/).*$//1 /2 /3 /4 /5 /6 /7 /8 /9/p" 1234 1234 1234 1 2 3 4 5 6 7 8 9 $


puedes usar grep

grep -Eow "[0-9]+" file


Renunciar y usar Perl

Ya que sed no lo corta, solo tiremos la toalla y usemos Perl, al menos es LSB mientras que las extensiones grep GNU no son :-)

  • Imprima toda la parte coincidente, no se necesitan grupos que coincidan o busque detrás de:

    cat <<EOS | perl -lane ''print m//d+/g'' a1 b2 a34 b56 EOS

    Salida:

    12 3456

  • Solo coincidencia por línea, a menudo campos de datos estructurados:

    cat <<EOS | perl -lape ''s/.*?a(/d+).*/$1/g'' a1 b2 a34 b56 EOS

    Salida:

    1 34

    Con lookbehind:

    cat <<EOS | perl -lane ''print m/(?<=a)(/d+)/'' a1 b2 a34 b56 EOS

  • Campos múltiples:

    cat <<EOS | perl -lape ''s/.*?a(/d+).*?b(/d+).*/$1 $2/g'' a1 c0 b2 c0 a34 c0 b56 c0 EOS

    Salida:

    1 2 34 56

  • Múltiples coincidencias por línea, a menudo datos no estructurados:

    cat <<EOS | perl -lape ''s/.*?a(/d+)|.*/$1 /g'' a1 b2 a34 b56 a78 b90 EOS

    Salida:

    1 34 78

    Con lookbehind:

    cat EOS<< | perl -lane ''print m/(?<=a)(/d+)/g'' a1 b2 a34 b56 a78 b90 EOS

    Salida:

    1 3478