Como extrair texto de uma string usando sed?

95

Minha string de exemplo é a seguinte:

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

Agora, da string acima, quero extrair 02G05. Para isso tentei o seguinte regex com sed

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

Mas o comando acima não imprime nada e a razão pela qual acredito é que ele não é capaz de corresponder nada ao padrão que forneci ao sed.

Portanto, minha pergunta é o que estou fazendo de errado aqui e como corrigi-lo.

Quando tento a string acima e o padrão com python, obtenho meu resultado

>>> re.findall(r'\d+G\d+',st)
['02G05']
>>>
RanRag
fonte
6
Python definitivamente não é sed. Seus sabores regex são bastante diferentes.
tripleee

Respostas:

91

O padrão \dpode não ser compatível com o seu sed. Experimente [0-9]ou em [[:digit:]]vez disso.

Para imprimir apenas a correspondência real (não toda a linha correspondente), use uma substituição.

sed -n 's/.*\([0-9][0-9]*G[0-9][0-9]*\).*/\1/p'
triplo
fonte
6
Obrigado, funcionou bem. Mas tenho uma dúvida porque .*é necessário com sua regex porque quando tento sed -n 's/\([0-9]\+G[0-9]\+\)/\1/p'apenas imprime a linha inteira.
RanRag
7
É por isso, não é? Substitua tudo o que vier antes e depois da correspondência por nada e, em seguida, imprima a linha inteira.
tripleee
1
@tripleee Isso só 2G05não imprime 02G05. A expressão que funciona é's/.*\([0-9][0-9]G[0-9][0-9]*\).*/\1/p'
Kshitiz Sharma
1
Isso o codifica para exatamente dois dígitos. Algo como sed -n 's/\(.*[^0-9]\)\?\([0-9][0-9]*G[0-9][0-9]*\).*/\2/p'seria mais geral. (Suponho que seus sedapoios \?para zero ou uma ocorrência.)
triplo
Veja também stackoverflow.com/a/48898886/874188 de como substituir vários outros comum Perl escapa como \w, \s, etc.
tripleee
98

Que tal usar grep -E?

echo "This is 02G05 a test string 20-Jul-2012" | grep -Eo '[0-9]+G[0-9]+'
mVChr
fonte
3
+1 Isto é mais simples e também tratará corretamente o caso de múltiplas correspondências na mesma linha. Um sedscript complexo poderia ser criado para esse caso, mas por que se preocupar?
tripleee de
egrepusa regexp estendida sede grepusa regexp padrão, egrepou grep -eou sed -Eusa regexp estendida, e o código python em questão usa PCRE (expressão regular comum de perl) GNU grep pode usar PCRE com -Popção.
Felipe Buccioni
@FelipeBuccioni na verdade deveria ser egrepou grep -Eoused -r
SensorSmith
Para uma única (primeira) correspondência, acrescente `| head -1` (sem backticks), conforme esta resposta a outra pergunta.
SensorSmith
1
greptem -m 1que parar após a primeira partida.
tripleee de
5

sednão reconhece \d, use em seu [[:digit:]]lugar. Você também precisará escapar do +ou usar a -rchave (-E no OS X).

Observe que isso [0-9]funciona bem para algarismos árabe-hindus.

Pausado até novo aviso.
fonte
Eu tentei sed -n '/[0-9]\+G[0-9]\+/p'. Agora, ele apenas imprime a string inteira
RanRag
@Noob: você precisará usar a substituição para excluir as partes que não deseja imprimir .
Pausado até novo aviso.
5

Em vez disso, tente isto:

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

Mas observe, se houver dois padrões em uma linha, ele imprimirá o segundo.

Zsolt Botykai
fonte
Ou, mais geralmente, o último se houver várias correspondências.
tripleee
0

Tente usar o rextract . Ele permitirá que você extraia o texto usando uma expressão regular e o reformate.

Exemplo:

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

2G05
Tim Savannah
fonte
Se isso usar regex padrão, os colchetes ao redor \dsão completamente supérfluos.
tripleee