Toon posts:

[sed] line end gebruiken in regexp

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik dien in een file bepaalde tekst rond een andere tekst te plaatsen.

Deze andere tekst varieert op verschillende plaatsen waarbij de begintekens en de eindtekens wel gekend zijn. bvb:

code:
1
HOOFDSTUK tekst die varieert Artikel


Dit vormt op zich geen probleem met de volgende code:
code:
1
sed 's/HOOFD[a-zA-Z0-9 .-]*Art/boe&boe/g' file.tex


Een deel van de tekst staat echter soms soms op een volgende (of de daaropvolgende) lijn.

Het opnemen van $ in de vierkante haakjes lever geen resultaat op (en \n ook niet).

Google biedt mij veel links over een regexp die eindigt op een line end maar ik vind geen terug waar een line end is opgenomen tussen de vierkante haken.

Weet iemand hoe ik regexp voor het deel tussen de vierkante haakjes kan uitbreiden over meerdere lijnen of dien ik eerst alle lijneindes te verwijderen zodat ik maar één regel tekst heb?

  • benoni
  • Registratie: November 2003
  • Niet online
Kun je even proberen of je met sed de 'multiline mode' switch kunt gebruiken (een m erbij zetten bij de flags achter de expressie).

Als het te ingewikkeld wordt voor sed (bijvoorbeeld met geneste markeringen of zo) kun je ook eens proberen met awk, daarmee kun je gedurende het proces variabelen gebruiken (bijvoorbeeld een tellertje laten meelopen die aangeeft hoe vaak je een beginteken bent tegengekomen).

Verwijderd

Topicstarter
benoni schreef op zaterdag 15 september 2007 @ 11:22:
Kun je even proberen of je met sed de 'multiline mode' switch kunt gebruiken (een m erbij zetten bij de flags achter de expressie).

[...]
Er is dus hoop. Alleen kan ik nog niet onmiddellijk vinden hoe ik die multiline mode kan aanzetten.

Je laat uitschijnen dat dit kan door een m te zetten maar ik vind dit niet terug in een manual.

Verwijderd

Verwijderd schreef op zaterdag 15 september 2007 @ 15:17:
[...]

Er is dus hoop. Alleen kan ik nog niet onmiddellijk vinden hoe ik die multiline mode kan aanzetten.

Je laat uitschijnen dat dit kan door een m te zetten maar ik vind dit niet terug in een manual.
Welke versie van SED gebruik je? de M modifier is namelijk een GNU extensie.

In de info pagina van de GNU versie staat het wel uitgelegd onder addresses (3.2)

code:
1
2
3
4
5
6
7
8
`/REGEXP/M'
`\%REGEXP%M'
     The `M' modifier to regular-expression matching is a GNU `sed'
     extension which causes `^' and `$' to match respectively (in
     addition to the normal behavior) the empty string after a newline,
     and the empty string before a newline.  There are special character
     sequences (`\`' and `\'') which always match the beginning or the
     end of the buffer.  `M' stands for `multi-line'.

Verwijderd

Topicstarter
ik gebruik sed 4.1.5 met de GNU extensions.

Bij de optie -s staat in de info (3.5) dat je M moet meegeven bij de flags.

Dus:
code:
1
sed -s /REGEXP/REPLACEMENT/M file.tex


Als ik de tekst als basis neem
code:
1
2
bla bla bla ontwricht
is


En daar zoek ik het stuk 'ontwricht is' op om het te vervangen
code:
1
sed -s '/ontwricht is/boe & boe/gM' file.tex


Dan krijg ik geen match, noch replacement. Ook niet als ik '/ontwricht[^$]*is/boe & boe/gM' of een variant gebruik.

Blijkbaar doe ik nog iets verkeerd. De vraag is nu wat.

  • benoni
  • Registratie: November 2003
  • Niet online
Mmm... dat multiple line werkt dus niet in sed, het moet trouwens ook niet met een hoofdletter M, en ik had het ook nog een beetje mis want het was juist de /s switch van 'single line' die relevant is.... :$

Even bij Perl gekeken (omdat je dat makkelijk zou kunnen gebruiken vanaf de command line):
Perl allows us to choose between ignoring and paying attention to newlines by using the //s and //m modifiers. //s and //m stand for single line and multi-line and they determine whether a string is to be treated as one continuous string, or as a set of lines. The two modifiers affect two aspects of how the regexp is interpreted: 1) how the '.' character class is defined, and 2) where the anchors ^ and $ are able to match. Here are the four possible combinations:

no modifiers (//): Default behavior. '.' matches any character except "\n" . ^ matches only at the beginning of the string and $ matches only at the end or before a newline at the end.

s modifier (//s): Treat string as a single long line. '.' matches any character, even "\n" . ^ matches only at the beginning of the string and $ matches only at the end or before a newline at the end.

m modifier (//m): Treat string as a set of multiple lines. '.' matches any character except "\n" . ^ and $ are able to match at the start or end of any line within the string.

both s and m modifiers (//sm): Treat string as a single long line, but detect multiple lines. '.' matches any character, even "\n" . ^ and $ , however, are able to match at the start or end of any line within the string.

Here are examples of //s and //m in action:

$x = "There once was a girl\nWho programmed in Perl\n";
$x =~ /^Who/; # doesn't match, "Who" not at start of string
$x =~ /^Who/s; # doesn't match, "Who" not at start of string
$x =~ /^Who/m; # matches, "Who" at start of second line
$x =~ /^Who/sm; # matches, "Who" at start of second line
$x =~ /girl.Who/; # doesn't match, "." doesn't match "\n"
$x =~ /girl.Who/s; # matches, "." matches "\n"
$x =~ /girl.Who/m; # doesn't match, "." doesn't match "\n"
$x =~ /girl.Who/sm; # matches, "." matches "\n"
Most of the time, the default behavior is what is want, but //s and //m are occasionally very useful. If //m is being used, the start of the string can still be matched with \A and the end of string can still be matched with the anchors \Z (matches both the end and the newline before, like $ ), and \z (matches only the end):

$x =~ /^Who/m; # matches, "Who" at start of second line
$x =~ /\AWho/m; # doesn't match, "Who" is not at start of string
$x =~ /girl$/m; # matches, "girl" at end of first line
$x =~ /girl\Z/m; # doesn't match, "girl" is not at end of string
$x =~ /Perl\Z/m; # matches, "Perl" is at newline before end
$x =~ /Perl\z/m; # doesn't match, "Perl" is not at end of string
Ik probeerde dus dit:
cat file.tex | perl -C -pe 's/ontwricht(.*)is/<boe> \1 <\/boe>/gsm'


Maar dat werkt (hier) niet, de Perl regular expression leest ook niet over de newlines heen. Kan zijn dat het niet 't juiste newline teken is, of dat ik de functie niet op de juiste manier gebruik...

Moet nu even weg, misschien dat iemand anders nu op ideeën komt, anders kom ik er later nog op terug O-)

Verwijderd

Verwijderd schreef op zondag 16 september 2007 @ 14:12:
ik gebruik sed 4.1.5 met de GNU extensions.

Bij de optie -s staat in de info (3.5) dat je M moet meegeven bij de flags.

Dus:
code:
1
sed -s /REGEXP/REPLACEMENT/M file.tex


Als ik de tekst als basis neem
code:
1
2
bla bla bla ontwricht
is


En daar zoek ik het stuk 'ontwricht is' op om het te vervangen
code:
1
sed -s '/ontwricht is/boe & boe/gM' file.tex


Dan krijg ik geen match, noch replacement. Ook niet als ik '/ontwricht[^$]*is/boe & boe/gM' of een variant gebruik.

Blijkbaar doe ik nog iets verkeerd. De vraag is nu wat.
Beetje vaag wat die multi line modus nou doet idd.

Maar ik heb het net even getest en het volgende werkt wel.

code:
1
sed -e 'N;s/ontwricht\nis/boe \& boe/' test.txt

Verwijderd

Topicstarter
Verwijderd schreef op zondag 16 september 2007 @ 19:03:
[...]

code:
1
sed -e 'N;s/ontwricht\nis/boe \& boe/' test.txt
Dit werkte in eerste instantie niet. Toen ik echter een andere testfile maakte werkte het wel.

Mijn tekst-file moet blijkbaar ergens nog een ander probleem veroorzaken maar de multi-line search lijkt nu wel te lukken.

  • deadinspace
  • Registratie: Juni 2001
  • Laatst online: 13:45

deadinspace

The what goes where now?

Verwijderd schreef op maandag 17 september 2007 @ 12:31:
Dit werkte in eerste instantie niet. Toen ik echter een andere testfile maakte werkte het wel.

Mijn tekst-file moet blijkbaar ergens nog een ander probleem veroorzaken maar de multi-line search lijkt nu wel te lukken.
Misschien gebruikt je originele tekstfile DOS newlines (\r\n) in plaats van Unix newlines (\n) ? File en hexdump zijn je vrienden om daarachter te komen :P
Pagina: 1