web-dev-qa-db-fra.com

Match de motif multiligne à l'aide de SED, AWK ou GREP

Est-il possible de faire une correspondance de modèle multiline à l'aide de sed, awk ou grep? Prenons par exemple, je voudrais obtenir toutes les lignes entre { et }

Donc, il devrait être capable de faire correspondre

 1. {}
 2. {.....}
 3. {.....
.....}

Initialement la question utilisée <p> par exemple. Édité la question à utiliser { et}.

26
user6106

Bien que je suis d'accord avec le conseil ci-dessus, que vous voudrez obtenir un analyseur pour quelque chose de plus que de minuscule ou totalement ad-hoc, c'est (à peine ;-) possible de faire correspondre des blocs multilignes entre les accessoires bouclés avec SED.

Voici une version de débogage du code SED

sed -n '/[{]/,/[}]/{
    p
    /[}]/a\
     end of block matching brace

    }' *.txt

Quelques notes,

  • -N signifie "pas de lignes d'impression par défaut comme traitées".
  • "P" signifie maintenant Imprimer la ligne.
  • La construction /[{]/,/[}]/ est une expression de plage. Cela signifie numériser jusqu'à ce que vous trouviez quelque chose qui correspond au premier modèle (/[{]/) Puis numériser jusqu'à ce que vous trouviez le 2e motif (/[}]/) Ensuite, effectuez toutes les actions que vous trouvez entre le {} dans le code SED. Dans ce cas, "P" et le code de débogage. (Non expliqué ici, utilisez-le, modez-le ou sortez-le comme fonctionne le mieux pour vous).

Vous pouvez supprimer le/[}]/a\fin du débogage du bloc lorsque vous prouvez à votre satisfaction que le code correspond vraiment à des blocs de correspondance délimités par {,}.

Cet échantillon de code sautera tout ce qui n'est pas à l'intérieur d'une paire d'attelle bouclée. Comme indiqué par d'autres personnes ci-dessus, être inconforté si vous avez un supplément {,} intégré dans des chaînes, des REG-EXPS, etc., ou où la brace de fermeture est la même ligne, (avec merci à fred.bear)

J'espère que ça aide.

19
shellter

Vous pouvez utiliser l'option -M (multiline) pour PCREGREP:

pcregrep -M '\{(\s*.*\s*)*\}' test.txt

\ s est blancheur (y compris de nouvelles lignes), cela correspond donc à zéro ou à plus d'occurrences de (Espace WhitSpace suivi de. * suivi de WhitSpace), toutes enfermées dans des accolades.

Mettre à jour:

Cela devrait faire la correspondance non gourmande:

pcregrep -n -M '\{(\n*.*?\n*)*?\}' test.txt
13
Cooper

parser.awk:

#!/usr/bin/awk -f    
function die(msg) { print msg > "/dev/stderr"; exit 1 }
BEGIN {
  FS=opener
  if (mode=="l") linewise=1
  else if (mode=="i") trim_closer=length(closer)
  else if (mode!="a") die("mode must be one of: l,i,a")
}
{
  live=level
  for (f=1; f<=NF; f++) {
    if (f>1) {
      live=++level
      if (mode=="i" && level>1 || mode=="a") printf "%s", opener
    }
    cur=$f
    level-=gsub(closer, "", cur)
    if (level<0) die("Unbalanced")
    if (!linewise) {
      cur=$f
      if (sub(".*" closer, "", cur)) printf "%s", 
        substr($f, 1, length($f) - length(cur) - (level ? 0 : trim_closer))
      else if (live) printf "%s", $f
    }
  }
  if (live) {
    if (linewise) print
    else print ""
  }
}
END { if (level>0) die("Unbalanced") }

Appeler comme awk -v'opener={' -v'closer=}' -v'mode=a' -f parser.awk. Si le mode est a, il imprime les supports et le contenu de tous les plus externes et équilibrés {...}; Si le mode est i, il imprime uniquement leur contenu; Si le mode est l, il imprime des lignes complètes où la plus externe {...} commence, reste ouvert ou ferme.

5
dubiousjim

XML comme des expressions telles que (étiquettes à infinie récursives) n'est pas une "langue régulière" ne peut donc pas être analysée par des expressions régulières (regex). Voici pourquoi:

https://stackoverflow.com/questions/1732348/regex-match-Open-tags-except-xhtml-elf-contenait-tags/

http://www.perlmonks.org/?node_id=66835

https://stackoverflow.com/questions/1379524/textual-protocol-qui-is-not-a-regular-language

5
Marcin

Les expressions régulières ne peuvent pas trouver des parenthèses imbriquées correspondant.

Si vous êtes certain qu'il n'y aura aucune paire de parenthèses imbriquée à l'intérieur de celle que vous recherchez, vous pouvez rechercher jusqu'à la première fermeture. Par exemple:

sed -r 's#\{([^}])\}#\1#'

Cela remplacera tout le texte de '{' à '}' avec ce qui entre entre eux.

1
mtk358