Comment extraire du texte d'une chaîne en utilisant sed?


95

Mon exemple de chaîne est le suivant:

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

Maintenant, à partir de la chaîne ci-dessus, je veux extraire 02G05. Pour cela j'ai essayé la regex suivante avec sed

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

Mais la commande ci-dessus n'imprime rien et la raison pour laquelle je pense est qu'elle n'est pas capable de faire correspondre quoi que ce soit avec le modèle que j'ai fourni à sed.

Donc, ma question est de savoir ce que je fais de mal ici et comment y remédier.

Quand j'essaye la chaîne et le modèle ci-dessus avec python, j'obtiens mon résultat

>>> re.findall(r'\d+G\d+',st)
['02G05']
>>>

6
Python ne l'est certainement pas sed. Leurs saveurs regex sont assez différentes.
tripleee

Réponses:


91

Le modèle \dn'est peut-être pas pris en charge par votre sed. Essayez [0-9]ou à la [[:digit:]]place.

Pour imprimer uniquement la correspondance réelle (et non la ligne de correspondance entière), utilisez une substitution.

sed -n 's/.*\([0-9][0-9]*G[0-9][0-9]*\).*/\1/p'

6
Merci, cela a bien fonctionné. Mais j'ai une question pourquoi .*est nécessaire avec votre regex parce que quand j'essaye, sed -n 's/\([0-9]\+G[0-9]\+\)/\1/p'il imprime juste la ligne entière.
RanRag

7
C'est pourquoi, n'est-ce pas? Remplacez ce qui vient avant et après le match par norhing, puis imprimez toute la ligne.
tripleee

1
@tripleee Ceci n'imprime 2G05pas seulement 02G05. L'expression qui fonctionne est's/.*\([0-9][0-9]G[0-9][0-9]*\).*/\1/p'
Kshitiz Sharma

1
Cela le code en dur à exactement deux chiffres. Quelque chose comme sed -n 's/\(.*[^0-9]\)\?\([0-9][0-9]*G[0-9][0-9]*\).*/\2/p'serait plus général. (Je suppose que vos sedsupports \?pour zéro ou un événement.)
tripleee

Voir aussi stackoverflow.com/a/48898886/874188 pour savoir comment remplacer divers autres Perl commun échappe comme \w, \s, etc.
tripleee

98

Que diriez-vous d'utiliser grep -E?

echo "This is 02G05 a test string 20-Jul-2012" | grep -Eo '[0-9]+G[0-9]+'

3
+1 C'est plus simple et traitera également correctement le cas de plusieurs correspondances sur la même ligne. Un sedscript complexe pourrait être conçu pour ce cas, mais pourquoi s'embêter?
tripleee

egreputilise une expression régulière étendue, sedet greputilise une expression régulière standard, egrepou grep -eou sed -Eutilise une expression régulière étendue, et le code python dans la question utilise PCRE, (expression régulière commune perl) GNU grep peut utiliser PCRE avec l' -Poption.
Felipe Buccioni

@FelipeBuccioni en fait qui devrait être egrepou grep -Eoused -r
SensorSmith

Pour une (première) seule correspondance, ajoutez `| head -1` (sans backticks), selon cette réponse à une autre question.
SensorSmith

1
grepdoit -m 1s'arrêter après le premier match.
tripleee

5

sedne reconnaît pas \d, utilisez à la [[:digit:]]place. Vous devrez également échapper +ou utiliser le -rcommutateur ( -Esous OS X).

Notez que cela [0-9]fonctionne également pour les chiffres arabes-hindous.


J'ai essayé sed -n '/[0-9]\+G[0-9]\+/p'. Maintenant, il imprime juste la chaîne entière
RanRag


5

Essayez plutôt ceci:

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

Mais notez que s'il y a deux motifs sur une ligne, il imprime le 2ème.


Ou plus généralement le dernier s'il y a plusieurs correspondances.
tripleee

0

Essayez d'utiliser rextract . Il vous permettra d'extraire du texte à l'aide d'une expression régulière et de le reformater.

Exemple:

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

2G05

Si cela utilise une expression régulière standard, les crochets autour \dsont complètement superflus.
tripleee
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.