2009-07-22 7 views
6

J'ai une commande sed que je veux exécuter sur un énorme, hideux, hideux fichier HTML qui a été créé à partir d'un document Microsoft Word. Tout ce qu'il doit faire est de supprimer toute instance de la chaîneCorrespond à n'importe quel caractère (y compris les nouvelles lignes) dans sed

style='text-align:center; color:blue; 
exampleStyle:exampleValue' 

La commande sed que je suis en train de modifier est

sed "s/ style='[^']*'//" fileA > fileB 

Il fonctionne très bien, sauf que chaque fois qu'il ya une nouvelle ligne à l'intérieur du texte correspondant, il ne correspond pas. Y a-t-il un modificateur pour sed, ou quelque chose que je peux faire pour forcer la correspondance de n'importe quel caractère, y compris les newlines? Je comprends que les regexps sont terribles en XML et HTML, bla bla bla, mais dans ce cas, les patterns de chaînes sont bien formés en ce que les attributs de style commencent toujours par un guillemet simple et se terminent par un guillemet simple. Donc, si je pouvais juste résoudre le problème de la nouvelle ligne, je pourrais réduire la taille du HTML de plus de 50% avec juste cette commande. En fin de compte, il s'est avéré que le script perl de Sinan Ünür fonctionnait le mieux. C'était presque instantané, et il a réduit la taille du fichier de 2,3 Mo à 850k. Good ol 'Perl ...

+0

sed est basé sur une ligne. C'est le point d'arrêt principal ici.Si vous utilisez le modificateur/g regex, il peut y avoir une option de ligne de commande pour l'obtenir pour lire le fichier comme une seule ligne, mais j'en doute (problèmes de mémoire et autres) –

+0

Il n'y a pas d'option (que je connaisse) pour lire un fichier en une seule ligne. J'utiliserais Perl pour ça. – Dana

+0

Mais sed dispose de moyens pour ajouter de nouvelles lignes dans l'espace de modèle et dans l'espace de stockage, il est donc possible de faire un traitement multi-lignes dans sed - ce n'est pas joli. – Beano

Répondre

2

sed passe par-dessus le fichier d'entrée ligne par ligne ce qui signifie, si je comprends bien, ce que vous voulez n'est pas possible dans sed.

Vous pouvez utiliser le script suivant Perl (non testé), bien que:

#!/usr/bin/perl 

use strict; 
use warnings; 

{ 
    local $/; # slurp mode 
    my $html = <>; 
    $html =~ s/ style='[^']*'//g; 
    print $html; 
} 

__END__ 

une doublure serait:

$ perl -e 'local $/; $_ = <>; s/ style=\047[^\047]*\047//g; print' fileA > fileB 
1

Vous pouvez supprimer tous les CR/LF en utilisant tr, exécutez sed, puis importer dans un éditeur qui prend en charge le formatage automatique.

3

Sed lit l'entrée ligne par ligne, il n'est donc pas simple de faire du traitement sur une ligne ... mais ce n'est pas impossible non plus, vous devez utiliser sed branching. Ce qui suit fonctionne, je l'ai commenté pour expliquer ce qui se passe (pas la syntaxe plus lisible!):

sed "# if the line matches 'style='', then branch to label, 
    # otherwise process next line 
    /style='/b style 
    b 
    # the line contains 'style', try to do a replace 
    : style 
    s/ style='[^']*'// 
    # if the replace worked, then process next line 
    t 
    # otherwise append the next line to the pattern space and try again. 
    N 
    b style 
" fileA > fileB 
1

Vous pouvez essayer ceci:

awk '/style/&&/exampleValue/{ 
    gsub(/style.*exampleValue\047/,"") 
} 
/style/&&!/exampleValue/{  
    gsub(/style.* /,"") 
    f=1   
} 
f &&/exampleValue/{ 
    gsub(/.*exampleValue\047 /,"") 
    f=0 
} 
1 
' file 

Sortie:

# more file 
this is a line 
    style='text-align:center; color:blue; exampleStyle:exampleValue' 
this is a line 
blah 
blah 
style='text-align:center; color:blue; 
exampleStyle:exampleValue' blah blah.... 

# ./test.sh 
this is a line 

this is a line 
blah 
blah 
blah blah.... 
+0

Ceci est mon vote pour la réponse. La progression des langues est sed -> awk -> C/C++/Ada. Commencez à gauche et avancez jusqu'à ce que vous ayez assez de puissance pour faire le travail. –

+0

peut ne pas être c/C++/Ada. IMO, peut-être Python/Perl/Ruby etc, au moins pour les tâches sysadmin. – ghostdog74

1

Une autre façon est comme:

$ cat toreplace.txt 
I want to make \ 
this into one line 

I also want to \ 
merge this line 

$ sed -e 'N;N;s/\\\n//g;P;D;' toreplace.txt 

sortie:

I want to make this into one line 

I also want to merge this line 

Les charges N une autre ligne, P imprime l'espace de motif à la première saut de ligne, et D supprime l'espace de motif à la première nouvelle ligne.

Questions connexes