Question Substituer un motif multiligne dans un fichier HTML


J'ai une série de fichiers HTML contenant deux lignes comme celle-ci:

<body>
<h1>Title</h1><p>
<a href="url">Description</a><br>

Je veux remplacer ce texte par quelque chose d'autre en utilisant un script bash. j'essaie

sed -i -r 's/<h1>Title.*?$\/^.*?<br>/Replacement text/1' filename.html

Mais ça ne fonctionne pas. Je suspecte que cela reste bloqué sur la nouvelle ligne et ne sachant pas comment contourner le problème.

Toute aide appréciée. N'hésitez pas à suggérer d'autres outils Linux autres que sed Tant que ça marche!


4
2018-05-19 17:01


origine


Avez-vous vraiment besoin sed pour ça? sed lit ligne par ligne, donc remplacer le texte multi-lignes est un peu fastidieux. - slhck
Je n'ai pas besoin d'utiliser sed. Je suis ouvert aux autres commandes linux. - To Do
oui, un motif traversant plusieurs lignes peut poser problème pour sed. - barlop


Réponses:


J'utiliserais Perl pour cela:

perl -0pe 's/<h1>Title.*\n.*<br>/replacement/' filename.html

Ici, -0 fait que Perl divise les enregistrements sur le NUL caractère au lieu de lire ligne par ligne, qui est la valeur par défaut lorsque vous utilisez le -p option.

Avec les expressions régulières Perl, vous avez besoin .*  pour correspondre à n'importe quel caractère plusieurs fois, et vous faites correspondre la nouvelle ligne avec \n.

Exemple:

$ echo '<body>
<h1>Title</h1><p>
<a href="url">Description</a><br>' | perl -0pe 's/<h1>Title.*\n.*<br>/replacement/'
<body>
replacement

9
2018-05-19 17:21



Et n'oublie pas, n'utilisez jamais d'expressions régulières pour analyser le HTML! :) - terdon
C'est presque bien. J'ai ajouté un? après les deux * pour désactiver la gourmandise. Est-il possible de faire la commande modifier le fichier au lieu de sortir vers STDOUT? - To Do
@ToDo Perl peut éditer sur place avec le -i option, donc courir perl -0p -i~ -e 's/…/…/' pour qu’il modifie le fichier original, en créant une copie de sauvegarde avec ~ comme suffixe. Ou, pour remplacer sans fichier de sauvegarde, appelez perl -0pi -e …. - slhck


sed ne peut pas correspondre plus d'une ligne directement. Lorsqu'un modèle multiligne est nécessaire, utilisez un outil plus puissant, tel que Perl:

perl -i~ -ne 'if (/^<h1>Title/) {
                  $n = <>;
                  if ($n =~ /<br>$/) { print "Replacement\n" }
                  else { print "$_$n" }
              } else { print }'

1
2018-05-19 17:22





Cela peut être fait avec sed.

sed -nf repl.sed filename.html

repl.sed contient:

# Must have one line loaded up before branching to rep.
# Processing will start this way.
:rep
# Load extra line into pattern space
N
# Test for title
/<h1>.*<\/h1><p>\n<a href=".*">.*<\/a><br>/{
  #Substitute and print
  s/<h1>\(.*\)<\/h1><p>\n<a href=".*">.*<\/a><br>/Title: \1/p
  #append next line without cycling
  N
  # everything but the last line
  s/.*\n\([.\n]*\)/\1/
  #test for last line
  ${
    p
    # this will effectively end the program
    n
  }
  b rep
}
${
  # will print pattern space (both lines)
  p
  # this will effectively end the program
  n
}
#Print first line in pattern space
P;
#Remove first line in pattern space with newline
s/.*\n\([.\n]*\)/\1/
b rep

Voir Travailler avec plusieurs lignes


1
2017-07-03 21:04