3 votes

Comment supprimer ou remplacer un texte multiligne entre deux modèles ?

Je voudrais ajouter des drapeaux clients dans certains de mes scripts pour qu'ils soient analysés avant d'être empaquetés par un scripts shell.

Disons qu'en supprimant tout le texte multiligne entre

^([#]|[//]){0,1}[_]+NOT_FOR_CUSTOMER_BEGIN[_]+\n

et entre

^([#]|[//]){0,1}[_]+NOT_FOR_CUSTOMER_END[_]+\n

Je veux qu'il soit tolérant aux erreurs (concernant le nombre de '_'), c'est pourquoi j'utilise des regex.

Par exemple :

avant.foo

i want this
#____NOT_FOR_CUSTOMER_BEGIN________
not this
nor this
#________NOT_FOR_CUSTOMER_END____
and this
//____NOT_FOR_CUSTOMER_BEGIN__
not this again
nor this again
//__________NOT_FOR_CUSTOMER_END____
and this again

deviendra :

après.foo

i want this
and this
and this again

Je préférerais utiliser sed mais toute solution intelligente sera la bienvenue :)

Quelque chose comme ça :

cat before.foo |  tr '\n' '\a' | sed -r 's/([#]|[//]){0,1}[_]+NOT_FOR_CUSTOMER_BEGIN[_]+\a.*\a([#]|[//]){0,1}[_]+NOT_FOR_CUSTOMER_END[_]+\a/\a/g' | tr '\a' '\n' > after.foo

5voto

anubhava Points 172509

sed est l'outil le plus simple à utiliser, car il peut supprimer les lignes d'un motif de début à un motif de fin :

sed -E '/_+NOT_FOR_CUSTOMER_BEGIN_+/,/_+NOT_FOR_CUSTOMER_END_+/d' file

i want this
and this
and this again

Si vous êtes à la recherche de awk alors voici une solution plus simple awk :

awk '/_+NOT_FOR_CUSTOMER_BEGIN_+/,/_+NOT_FOR_CUSTOMER_END_+/{next} 1' file

4voto

RavinderSingh13 Points 29608

Avoir awk de cette façon, écrit et testé avec vos échantillons montrés.

awk '
/^([#]|[/][/])__+NOT_FOR_CUSTOMER_BEGIN/{ found=1       }
/^([#]|[/][/])__+NOT_FOR_CUSTOMER_END/  { found=""; next}
!found
'  Input_file

Avec les échantillons que vous avez montrés, la sortie sera la suivante.

i want this
and this
and this again

Explication : L'explication simple est la suivante : chaque fois qu'une chaîne de début (avec regex) est trouvée, un drapeau est mis à VRAI (pour ne pas imprimer) et chaque fois qu'une chaîne de fin (avec regex) est trouvée, le drapeau est annulé pour commencer à imprimer (selon les lignes) la ligne suivante.

3voto

Jan Points 370

Vous pourriez utiliser un Python script :

import re

data = """
i want this
#____NOT_FOR_CUSTOMER_BEGIN________
not this
nor this
#________NOT_FOR_CUSTOMER_END____
and this
//____NOT_FOR_CUSTOMER_BEGIN__
not this again
nor this again
//__________NOT_FOR_CUSTOMER_END____
and this again
"""

rx = re.compile(r'^(#|//)(?:.+\n)+^\1.+\n?', re.MULTILINE)
data = rx.sub('', data)
print(data)

Ce qui donnerait

i want this
and this
and this again

Voir une démo sur regex101.com .

3voto

The fourth bird Points 40138

Vous pourriez faire correspondre le moins possible les lignes de NOT_FOR_CUSTOMER_BEGIN_ jusqu'à NOT_FOR_CUSTOMER_END_

Notez que [//] correspond à un seul / au lieu de //

^(?:#|//)_+NOT_FOR_CUSTOMER_BEGIN_+(?:\n.*)*?\n(?:#|//)_+NOT_FOR_CUSTOMER_END_+\n*
  • ^ Début de la chaîne de caractères
  • (?:#|//) Correspondre soit # o //
  • _+NOT_FOR_CUSTOMER_BEGIN_+ Match NOT_FOR_CUSTOMER_BEGIN entre 1 ou plusieurs caractères de soulignement
  • (?:\n.*)*? Répétez le moins de lignes possible
  • \n(?:#|//)_+NOT_FOR_CUSTOMER_END_+ Correspond à une nouvelle ligne, puis soit # o // y NOT_FOR_CUSTOMER_END_ entre un ou plusieurs traits de soulignement
  • \n* Suppression des nouvelles lignes de fin facultatives

Démonstration de Regex

Une autre façon de l'utiliser avec Python :

import re

regex = r"^(?:#|//)_+NOT_FOR_CUSTOMER_BEGIN_+(?:\n.+)*?\n(?:#|//)_+NOT_FOR_CUSTOMER_END_+\n*"

s = ("i want this\n"
            "#____NOT_FOR_CUSTOMER_BEGIN________\n"
            "not this\n"
            "nor this\n"
            "#________NOT_FOR_CUSTOMER_END____\n"
            "and this\n"
            "//____NOT_FOR_CUSTOMER_BEGIN__\n"
            "not this again\n"
            "nor this again\n"
            "//__________NOT_FOR_CUSTOMER_END____\n"
            "and this again")

subst = ""
result = re.sub(regex, "", s, 0, re.MULTILINE)

if result:
    print (result)

Sortie

i want this
and this
and this again

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X