Thread View: comp.editors
3 messages
3 total messages
Started by Eric Pement
Sun, 22 Oct 1995 00:00
SED q. re multiline patterns (long)
Author: Eric Pement
Date: Sun, 22 Oct 1995 00:00
Date: Sun, 22 Oct 1995 00:00
77 lines
3931 bytes
3931 bytes
An advanced SED question involving multi-line patterns (I'm using GNU sed
v1.5 by Howard Helman, compiled for MS-DOS, but I think this applies to
several varieties of SED):
I want to remove a block of 4 contiguous lines which recur at repeated
intervals throughout several files. The first line of each block is
always a blank line. However, the input files also contain groups of 1
or more blank lines which should not be deleted. My problem arises when
the block to be deleted is preceded by 1 or more blank lines. E.g.,
1: aaa aaaa # (Line numbers added for clarity)
2: bbb bbbb
3:
4: # Lines #4-7, inclusive,
5: xxxx # should be deleted from
6: yyyy # the input stream.
7: zzzz #
8: ccc cccc
9: ddd dddd
I have tried writing many SED scripts to delete this pattern, with
varying degrees of success. My best effort is this one:
/^$/ { # locate a blank line
N # .. append the next line to pattern space
/xxxx/ D # .. if "xxxx" is in the space, delete blank line
} # only the second line will be output.
/xxxx/ { # locate lines with "xxxx"
N # .. read in the next 2 lines
N
d # .. delete the pattern space
} # end of script
However, this script fails in cases such as the one given above, since
when lines 3: and 4: are read into the pattern space, the first test
fails and both lines are output. The SED script will skip line 4: since
the N command read it already, and program flow proceeds to line 5:.
The result is that line 4: (which should have been deleted) is not
deleted from the output.
Since blank lines can appear anywhere in the input file, there may be
two or even 3 blank lines before the deletion block. I have tried
writing other tests for the next two lines after a blank line, but the
problem is that SED program logic jumps to the NEXT line read after the
last "N" command rather than iterating on each line.
If anyone can offer some suggestions about resolving this problem using
SED, I would certainly appreciate it.
Some reflections. I have thought of two potential solutions to solve
difficulties such as this, which would (to my knowledge) require
expanding SED's pattern matching abilities. Perhaps for GNU wizards?
(1) offering MINIMAL matching for two addresses. The command
/^$/,/zzzz/ d
will delete lines 3-7, inclusive, since SED range addressing is
a maximal match. An option for minimal range addressing would
delete the lines 4-7 only.
(2) offering multi-line direct addressing. For example:
/^\nxxxx\nyyyy\zzzz$/ d # one possible syntax
/^$\n^xxxx$\n^yyyy$\n^zzzz$/ d # another possible syntax
One of these suggested syntaxes, which would not require using
the "N" function (and thus skip other lines of input), would be
helpful for resolving problems such as these.
I would appreciate any feedback or reflections on the above. Thanks.
If I should be posting this query in a different newsgroup, please let me
know; this is the closest match I could come to. (E-mail replies okay.)
--
Eric Pement <epement@ripco.com>
Re: SED q. re multiline patterns (long)
Author: G. Ioannou
Date: Sun, 22 Oct 1995 00:00
Date: Sun, 22 Oct 1995 00:00
75 lines
3590 bytes
3590 bytes
In article <DGtuuq.AJ@rci.ripco.com>, Eric Pement <epement@ripco.com> wrote:
[...]
>I want to remove a block of 4 contiguous lines which recur at repeated
>intervals throughout several files. The first line of each block is
>always a blank line. However, the input files also contain groups of 1
>or more blank lines which should not be deleted. My problem arises when
>the block to be deleted is preceded by 1 or more blank lines. E.g.,
>
> 1: aaa aaaa # (Line numbers added for clarity)
> 2: bbb bbbb
> 3:
> 4: # Lines #4-7, inclusive,
> 5: xxxx # should be deleted from
> 6: yyyy # the input stream.
> 7: zzzz #
> 8: ccc cccc
> 9: ddd dddd
>
[...]
>Since blank lines can appear anywhere in the input file, there may be
>two or even 3 blank lines before the deletion block. I have tried
>writing other tests for the next two lines after a blank line, but the
>problem is that SED program logic jumps to the NEXT line read after the
>last "N" command rather than iterating on each line.
I think the following sed script should do the trick:
:loop
$b
/^$/{
N
/\nxxxx$/b success
P
D
}
n
b loop
:success
N
N
d
This script uses a technique I learned from Dale Dougherty's book,
`sed & awk', published by O'Reilly and Associates. He calls this the
input/output loop, and explains it in the chapter on `Advanced Sed
Commands'. The logic behind this is as follows:
The script is composed of two parts, the i/o loop and the success
routine. As long as the current line is not blank, sed simply reaches
the n command, followed by an unconditional branch to the top of the
script, and therefore outputs the current line and starts from the
beginning with the next line. As soon as a blank line is encountered,
the i/o loop is entered: the next line is appended to the pattern
space; if this line does not match xxxx, then the blank line is output
and then deleted (P then D). The D command causes sed to start from
the beginning, USING THE LINE ALREADY IN THE PATTERN SPACE, NOT THE
NEXT LINE. This is really the essence of the technique.
Now if the appended line matches xxxx, a branch is made to the success
label. This appends the following two lines (yyyy and zzzz) and then
deletes the lot, from the blank line to zzzz inclusive. The next line
is read in and sed starts from the beginning.
I have assumed that a blank line followed by xxxx is always a success,
in other words, that lines yyyy and zzzz always follow xxxx after a
blank. If this is not true, then additional checking is needed in the
success routine.
I have put a `$b' command right after the :loop label, because
otherwise the script will not output the last line of input if it is
blank, presumably because the N command fails? Anyway, this trick
seems to correct the problem.
Hope this helps.
-George.
Re: SED q. re multiline patterns (long)
Author: Eric Pement
Date: Tue, 24 Oct 1995 00:00
Date: Tue, 24 Oct 1995 00:00
91 lines
4580 bytes
4580 bytes
G. Ioannou (gi101@cus.cam.ac.uk) wrote:
: In article <DGtuuq.AJ@rci.ripco.com>, Eric Pement <epement@ripco.com> wrote:
: [...]
: >I want to remove a block of 4 contiguous lines which recur at repeated
: >intervals throughout several files. The first line of each block is
: >always a blank line. However, the input files also contain groups of 1
: >or more blank lines which should not be deleted. My problem arises when
: >the block to be deleted is preceded by 1 or more blank lines. E.g.,
: >
: > 1: aaa aaaa # (Line numbers added for clarity)
: > 2: bbb bbbb
: > 3:
: > 4: # Lines #4-7, inclusive,
: > 5: xxxx # should be deleted from
: > 6: yyyy # the input stream.
: > 7: zzzz #
: > 8: ccc cccc
: > 9: ddd dddd
: >
: [...]
: >Since blank lines can appear anywhere in the input file, there may be
: >two or even 3 blank lines before the deletion block. I have tried
: >writing other tests for the next two lines after a blank line, but the
: >problem is that SED program logic jumps to the NEXT line read after the
: >last "N" command rather than iterating on each line.
: I think the following sed script should do the trick:
: :loop
: $b
: /^$/{
: N
: /\nxxxx$/b success
: P
: D
: }
: n
: b loop
: :success
: N
: N
: d
: This script uses a technique I learned from Dale Dougherty's book,
: `sed & awk', published by O'Reilly and Associates. He calls this the
: input/output loop, and explains it in the chapter on `Advanced Sed
: Commands'. The logic behind this is as follows:
: The script is composed of two parts, the i/o loop and the success
: routine. As long as the current line is not blank, sed simply reaches
: the n command, followed by an unconditional branch to the top of the
: script, and therefore outputs the current line and starts from the
: beginning with the next line. As soon as a blank line is encountered,
: the i/o loop is entered: the next line is appended to the pattern
: space; if this line does not match xxxx, then the blank line is output
: and then deleted (P then D). The D command causes sed to start from
: the beginning, USING THE LINE ALREADY IN THE PATTERN SPACE, NOT THE
: NEXT LINE. This is really the essence of the technique.
: Now if the appended line matches xxxx, a branch is made to the success
: label. This appends the following two lines (yyyy and zzzz) and then
: deletes the lot, from the blank line to zzzz inclusive. The next line
: is read in and sed starts from the beginning.
: I have assumed that a blank line followed by xxxx is always a success,
: in other words, that lines yyyy and zzzz always follow xxxx after a
: blank. If this is not true, then additional checking is needed in the
: success routine.
: I have put a `$b' command right after the :loop label, because
: otherwise the script will not output the last line of input if it is
: blank, presumably because the N command fails? Anyway, this trick
: seems to correct the problem.
: Hope this helps.
: -George.
It does indeed. I quoted your ENTIRE message, since I am so impressed with
your worthwhile and perceptive response. Actually, I have Dougherty's book,
"SED & AWK", and had worked my way through pp. 117-119 (the section you
referred to), but seeing your explanation above in light of my particular
problem put things in a different, and better, perspective.
Thanks so much. I suspected that sed should be able to handle a problem of
this nature, and am glad that my intuitions here were on target. Now I
wonder about getting something like minimal range matching...<grin>. Thanx
again for your assistance.
Kind regards,
Eric Pement <epement@ripco.com>
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads