2009-07-22 11 views
6

Ich habe eine sed Befehl, den ich auf eine riesige, schreckliche, hässliche HTML-Datei, die aus einem Microsoft Word-Dokument erstellt wurde, ausführen möchte. Alles, was sie tun sollen, ist eine Instanz der Zeichenfolge entfernenEin beliebiges Zeichen (einschließlich Zeilenumbrüche) in sed

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

Der sed Befehl, den ich ist

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

Es funktioniert großartig, mit der Ausnahme, dass zu ändern versuchen, wann immer es eine neue Linie innerhalb dem ist passender Text, stimmt nicht überein. Gibt es einen Modifikator für sed oder etwas, das ich tun kann, um die Übereinstimmung eines beliebigen Zeichens zu erzwingen, einschließlich Zeilenumbrüchen?

Ich verstehe, dass Regexps bei XML und HTML schrecklich sind, blah blah blah, aber in diesem Fall sind die String-Muster wohlgeformt, da die Style-Attribute immer mit einem einfachen Zitat beginnen und mit einem einzigen Zitat enden. Wenn ich also nur das Newline-Problem lösen könnte, könnte ich die HTML-Größe mit nur einem Befehl um mehr als 50% reduzieren.


Am Ende stellte sich heraus, dass Sinan Ünürs Perl-Skript am besten funktionierte. Es war fast augenblicklich und reduzierte die Dateigröße von 2,3 MB auf 850 KB. Good ol 'Perl ...

+0

sed ist linienbasiert. Das ist der wichtigste Haltepunkt hier.Wenn Sie den Modifikator/g regex verwenden, gibt es möglicherweise eine Befehlszeilenoption, um die Datei als einzelne Zeile zu lesen, aber ich bezweifle es (Speicherprobleme und ähnliches) –

+0

Es gibt keine Option (die ich kenne) zum Lesen einer Datei als einzelne Zeile. Ich würde Perl dafür benutzen. – Dana

+0

Aber sed hat Mittel, um neue Zeilen in den Musterbereich und den Haltebereich einzufügen, so dass es möglich ist, in sed mehrere Zeilen zu verarbeiten - es ist einfach nicht hübsch. – Beano

Antwort

2

sed geht über die Eingabedatei Zeile für Zeile, was bedeutet, dass, wie ich verstehe, was Sie wollen, ist nicht möglich in sed.

Sie könnten das folgende Perl-Skript (ungetestet) verwenden, aber:

#!/usr/bin/perl 

use strict; 
use warnings; 

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

__END__ 

Ein Motto wäre:

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

Sie könnten alle CR/LF entfernen tr verwenden, führen sed, und importieren Sie dann in einen Editor, der automatisch formatiert.

3

Sed liest die Eingabe Zeile für Zeile, so ist es nicht einfach, die Verarbeitung über eine Zeile zu tun ... aber es ist auch nicht unmöglich, Sie müssen sed Verzweigung verwenden. Im Folgenden wird arbeiten, ich habe es kommentiert, zu erklären, was los ist (nicht die meisten lesbare Syntax!):

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

können Sie versuchen, diese:

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

Ausgang:

# 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

Das ist meine Stimme für die Antwort. Der Fortschritt der Sprachen ist sed -> awk -> C/C++/Ada. Beginnen Sie auf der linken Seite und bewegen Sie sich nach rechts, bis Sie genug Kraft haben, um die Arbeit zu erledigen. –

+0

ist möglicherweise nicht c/C++/Ada. IMO, vielleicht Python/Perl/Ruby etc, zumindest für Sysadmin-Aufgaben. – ghostdog74

1

Ein anderer Weg ist, wie:

$ 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 

Ausgabe:

I want to make this into one line 

I also want to merge this line 

Die N lädt eine andere Linie, P druckt den Musterraum zur ersten Newline auf und D löscht den Musterraum zur ersten Newline auf.

Verwandte Themen