¿Cómo extraer texto de una cadena usando sed?

96

Mi cadena de ejemplo es la siguiente:

This is 02G05 a test string 20-Jul-2012

Ahora de la cadena de arriba quiero extraer 02G05. Para eso probé la siguiente expresión regular con sed

$ echo "This is 02G05 a test string 20-Jul-2012" | sed -n '/\d+G\d+/p'

Pero el comando anterior no imprime nada y la razón por la que creo es que no puede hacer coincidir nada con el patrón que proporcioné a sed.

Entonces, mi pregunta es qué estoy haciendo mal aquí y cómo corregirlo.

Cuando pruebo la cadena y el patrón anteriores con python, obtengo mi resultado

>>> re.findall(r'\d+G\d+',st)
['02G05']
>>>
RanRag
fuente
6
Python definitivamente no lo es sed. Sus sabores de expresiones regulares son bastante diferentes.
tripleee

Respuestas:

92

Es \dposible que el patrón no sea compatible con su sed. Prueba [0-9]o en su [[:digit:]]lugar.

Para imprimir solo la coincidencia real (no toda la línea coincidente), utilice una sustitución.

sed -n 's/.*\([0-9][0-9]*G[0-9][0-9]*\).*/\1/p'
triples
fuente
6
Gracias, funcionó bien. Pero tengo una pregunta de por qué .*es necesario con su expresión regular porque cuando lo intento sed -n 's/\([0-9]\+G[0-9]\+\)/\1/p'solo imprime la línea completa.
RanRag
7
Por eso, ¿no es así? Reemplace lo que venga antes y después de la coincidencia con norhing, luego imprima la línea completa.
tripleee
1
@tripleee Esto solo imprime 2G05no 02G05. La expresión que funciona es's/.*\([0-9][0-9]G[0-9][0-9]*\).*/\1/p'
Kshitiz Sharma
1
Eso lo codifica exactamente a dos dígitos. Algo así sed -n 's/\(.*[^0-9]\)\?\([0-9][0-9]*G[0-9][0-9]*\).*/\2/p'sería más general. (Asumo sus sedapoyos \?para cero o una ocurrencia)
tripleee
Consulte también stackoverflow.com/a/48898886/874188 para saber cómo reemplazar varios otros escapes de Perl comunes como \w,\s , etc.
tripleee
99

¿Qué tal usar grep -E?

echo "This is 02G05 a test string 20-Jul-2012" | grep -Eo '[0-9]+G[0-9]+'
mVChr
fuente
3
+1 Esto es más simple y también manejará correctamente el caso de múltiples coincidencias en la misma línea. Se sedpodría idear un guión complejo para ese caso, pero ¿para qué molestarse?
tripleee
egrepPosibilidades de ampliar expresión regular, sedy greputiliza expresiones regulares estándar, egrepo grep -eo sed -Eusan expresión regular extendida, y el código Python en la pregunta utiliza PCRE, (Perl expresiones regulares común) GNU grep puede utilizar PCRE con -Popción.
Felipe Buccioni
@FelipeBuccioni en realidad debería ser egrepo grep -Eosed -r
SensorSmith
Para una única (primera) coincidencia, agregue `| head -1` (sin comillas invertidas), según esta respuesta a otra pregunta.
SensorSmith
1
greptiene -m 1que parar después del primer partido.
tripleee
5

sedno reconoce \d, use [[:digit:]]en su lugar. También necesitará escapar +o usar el -rinterruptor ( -Een OS X).

Tenga en cuenta que [0-9]funciona también para números arábigos-hindúes.

Pausado hasta nuevo aviso.
fuente
Lo intenté sed -n '/[0-9]\+G[0-9]\+/p'. Ahora solo imprime la cadena completa
RanRag
@Noob: Deberá usar la sustitución para excluir las partes que no desea imprimir .
Pausado hasta nuevo aviso.
5

Prueba esto en su lugar:

echo "This is 02G05 a test string 20-Jul-2012" | sed 's/.* \([0-9]\+G[0-9]\+\) .*/\1/'

Pero tenga en cuenta que si hay dos patrones en una línea, imprimirá el segundo.

Zsolt Botykai
fuente
O más generalmente el último si hay múltiples coincidencias.
tripleee
0

Intente usar rextract . Le permitirá extraer texto usando una expresión regular y reformatearlo.

Ejemplo:

$ echo "This is 02G05 a test string 20-Jul-2012" | ./rextract '([\d]+G[\d]+)' '${1}'

2G05
Tim Savannah
fuente
Si esto usa expresiones regulares estándar, los corchetes alrededor \dson completamente superfluos.
tripleee