[comp.editors] ex search & substitution question

brent@hprnd.HP.COM (Brent McInnis) (08/07/90)

I want to search a range of lines for the patterns such as

#i55
#u55
#t55

at the beginning of a line, and change them to 

#i71
#u71
#t71

I understand that I can use

:/^#[iut]55/s/55/71/

To perform this operation on the *next* line,

and I understand that I can use

:g/^#[iut]55/s/55/71/

to perform this operation on *all* lines in the file.

But to perform it on a *range* of lines (say, lines 10 thru 20), I
*want* to say

:10,20/^#[iut]55/s/55/71/

But ex responds with a "Badly formed address" error.

Note that I don't want to do something as simple as

:10,20s/55/71

because of the risk of this changing *other* lines within the specified range
with 55's in them to 71's.

I want to search a specific range for the specific pattern consisting of
the beginning of a line, followed by the hash, followed by one of the
specfic letters I mentioned, followed by 55, and change *only those*
55's to 71's.

Is it impossible to do what I am trying to do in ex?

Thanks,

============================================================================

                               Brent McInnis  
Roseville Networks Division                     Mailstop R3NF2
System Interface Lab                            HP Telnet 785-4536
brent@hprnd.hp.com                              Long Distance (916) 785-4536

new@ee.udel.edu (Darren New) (08/07/90)

In article <3440001@hprnd.HP.COM> brent@hprnd.HP.COM (Brent McInnis) writes:
>But to perform it on a *range* of lines (say, lines 10 thru 20), I
>*want* to say
>:10,20/^#[iut]55/s/55/71/

Try 
:10,20g/^#[iut]55/s/55/71/

I think you can give a range to the g command to have it operate on the lines
within the range that also match the pattern.       -- Darren

sanjiv@hoss.unl.edu (Sanjiv K. Bhatia) (08/08/90)

In article <26814@nigel.ee.udel.edu> new@ee.udel.edu (Darren New) writes:
>In article <3440001@hprnd.HP.COM> brent@hprnd.HP.COM (Brent McInnis) writes:
>>But to perform it on a *range* of lines (say, lines 10 thru 20), I
>>*want* to say
>>:10,20/^#[iut]55/s/55/71/
>
>Try 
>:10,20g/^#[iut]55/s/55/71/
>
>I think you can give a range to the g command to have it operate on the lines
>within the range that also match the pattern.       -- Darren

Here is my $0.02 worth.  I prefer to use the substitute command 's'.

:10,20s/^#[iut]55/77/

Sanjiv
--
Sanjiv K. Bhatia				Department of Computer Science
sanjiv@fergvax.unl.edu				Ferguson Hall 115
voice: (402)-472-3485				University of Nebraska - Lincoln
fax:   (402)-472-7767				Lincoln, NE 68588-0115

wnp@iiasa.AT (wolf paul) (08/08/90)

In article <1990Aug07.174235.28911@hoss.unl.edu> sanjiv@hoss.unl.edu (Sanjiv K. Bhatia) writes:
>In article <3440001@hprnd.HP.COM> brent@hprnd.HP.COM (Brent McInnis) writes:
>>But to perform it on a *range* of lines (say, lines 10 thru 20), I
>>*want* to say
>>:10,20/^#[iut]55/s/55/71/
>
>Here is my $0.02 worth.  I prefer to use the substitute command 's'.
>
>:10,20s/^#[iut]55/71/


NO, that won't work. It will replace the entire matched string
#[iut]55 with just the two digits 71.

You need to save the first part of the matched string using the \( \)
operators, and then interpolate them in the substitution string with
\1, like this:

  :10,20s/^\(#[iut]\)55/\177/

This says, in effect:

 "At the beginning of the line, locate and save '#[iut]', if it is
 followed by '55'.
 Substitute for the entire matched string the saved portion followed
 by 71."

The \( \) operators save the matched string specified by the RE
between them for later interpolation into the substitute string; if
you use just one pair of \( \), the interpolation takes the form
'\1', if you use several pairs successively, use '\1', '\2', etc.

Hope this helps.
-- 
Wolf N. Paul, Int. Institute for Applied Systems Analysis (IIASA)
Schloss Laxenburg, Schlossplatz 1, A - 2361 Laxenburg, Austria, Europe
PHONE: +43-2236-71521-465     FAX: +43-2236-71313      UUCP: uunet!iiasa.at!wnp
INTERNET: wnp%iiasa.at@uunet.uu.net      BITNET: tuvie!iiasa!wnp@awiuni01.BITNET

steveha@microsoft.UUCP (Steve Hastings) (08/08/90)

In article <1990Aug07.174235.28911@hoss.unl.edu> sanjiv@hoss.unl.edu (Sanjiv K. Bhatia) writes:
>In article <26814@nigel.ee.udel.edu> new@ee.udel.edu (Darren New) writes:
>>Try 
>>:10,20g/^#[iut]55/s/55/71/
>>
>
>Here is my $0.02 worth.  I prefer to use the substitute command 's'.
>
>:10,20s/^#[iut]55/77/

This will replace everything with "77".  Try this:

:10,20s/^\(#[iut]\)55/\177/
         ^^      ^^   ^^

The \( \) quotes part of the match pattern, and the \1 evaluates to the
quoted pattern.  You can have up to 9 pairs of \( \), referred to as \1 to \9
in the replacement part.  But for this example, I think the g// is better.
-- 
Steve "I don't speak for Microsoft" Hastings    ===^=== :::::
uunet!microsoft!steveha  steveha@microsoft.uucp    ` \\==|

dattier@ddsw1.MCS.COM (David W. Tamkin) (08/09/90)

Sanjiv K. Bhatia wrote in <1990Aug07.174235.28911@hoss.unl.edu>, answering
Darren New's response to Brent McInnis:

DN> Try 
DN> :10,20g/^#[iut]55/s/55/71/

DN> I think you can give a range to the g command to have it operate on the 
DN> lines within the range that also match the pattern.       -- Darren

Yes, you can give a firstline,lastline range and then a g or v within it, but
you cannot nest a g or a v within a[nother] g or v.

SKB> Here is my $0.02 worth.  I prefer to use the substitute command 's'.
SKB> :10,20s/^#[iut]55/77/

Not quite, Sanjiv.  That will lose the # and the letter, replacing all four
characters with just "77".

Darren's suggestion of :10,20 g/^#[iut]55/s/55/71/ will work *for this
situation*.  It says to look for #[iut]55 at the beginning of any of those
eleven lines in the numeric range and change the leftmost 55 to 71 in every
line containing that pattern.  It depends, however, on the expression's being
anchored to the left end of the line, or there would be a risk of changing the
wrong 55 to 71 if 55 occurs again farther leftward in the line.  It also
depends on the first part of the search expression's not containing the last
part: if Brent had wanted to change /^5555/ to 5571, he'd get 7155!

:10,20 s/^\(#[itu]\)55/\171/ gets around that problem; it says to look for
the four-character pattern and change the 55 in its last two characters to
71, leaving the first two characters unaltered, regardless of what they were.
Its reasoning can be applied to search patterns that are not left-edge
anchored.  I like the logic behind this method better, but in this particular
case the risks in Darren's advice are not present, and I find his way less
subject than my own to the particular typing errors I'm prone to make.
(Neither method requires a space after the 20; it's just another personal
preference of mine, as was alphabetizing [itu].)

David Tamkin  Box 7002  Des Plaines IL  60018-7002  708 518 6769  312 693 0591
MCI Mail: 426-1818  GEnie: D.W.TAMKIN  CIS: 73720,1570   dattier@ddsw1.mcs.com

edp367s@monu6.cc.monash.edu.au (Rik Harris) (08/09/90)

sanjiv@hoss.unl.edu (Sanjiv K. Bhatia) writes:

>In article <26814@nigel.ee.udel.edu> new@ee.udel.edu (Darren New) writes:
>>In article <3440001@hprnd.HP.COM> brent@hprnd.HP.COM (Brent McInnis) writes:
>>>But to perform it on a *range* of lines (say, lines 10 thru 20), I
>>>*want* to say
>>>:10,20/^#[iut]55/s/55/71/
>>within the range that also match the pattern.       -- Darren

[stuff deleted]

>Here is my $0.02 worth.  I prefer to use the substitute command 's'.

>:10,20s/^#[iut]55/77/

no, this will delete the letter at the start, the letter must stay.

a more complicated solution is required:

:10,20s/\(^#[iut]\)55/\177/

this puts the letter at the start in a variable called \1, and replaces the
whole string with the letter followed by the 77.

I e-mailed the author of the original article, but it looks like there's some
others who might benefit from this.

rik.

-------------------------------------------------------------------------------
Rik Harris - Monash University, Caulfield Campus (was Chisholm Institute)
edp367s@monu6.cc.monash.edu.au     <-- what the computer says it is
edp367s@monu6.cc.monash.oz[.au]    <-- SEEMS to work more reliably
Build a system that even a fool can use, and only a fool will want to use it.
-------------------------------------------------------------------------------

jsdy@hadron.COM (Joseph S. D. Yao) (08/10/90)

In article <1990Aug9.003212.12140@monu6.cc.monash.edu.au> edp367s@monu6.cc.monash.edu.au (Rik Harris) writes:
>sanjiv@hoss.unl.edu (Sanjiv K. Bhatia) writes:
>>:10,20s/^#[iut]55/77/
>a more complicated solution is required:
>:10,20s/\(^#[iut]\)55/\177/

Just to note that the left anchor, '^', must be outside the escaped
parentheses.  While this works, I'd prefer the
	:10,20g/^#[iut]55/s/55/71/
[note corrected second number] technique, because I sometimes make
mistakes typing in the more complicated expressions.  It is always
possible to find a correct substitute command; I don't know why one
person complained that this way led to errors.  But both work, so
whichever works best for YOU is the one you should use.

	Joe Yao				jsdy@hadron.COM
	( jsdy%hadron.COM@{uunet.UU.NET,decuac.DEC.COM} )
	arc,arinc,att,avatar,blkcat,cos,decuac,\
	dtix,ecogong,grebyn,inco,insight,kcwc,  \
	lepton,lsw,netex,netxcom,phw5,research,  >!hadron!jsdy
	rlgvax,seismo,sms,smsdpg,sundc,telenet, /
	uunet				       /
(Last I counted ...)

staff@cadlab.sublink.ORG (Alex Martelli) (08/10/90)

new@ee.udel.edu (Darren New) writes:

>In article <3440001@hprnd.HP.COM> brent@hprnd.HP.COM (Brent McInnis) writes:
>>But to perform it on a *range* of lines (say, lines 10 thru 20), I
>>*want* to say
>>:10,20/^#[iut]55/s/55/71/

>Try 
>:10,20g/^#[iut]55/s/55/71/

>I think you can give a range to the g command to have it operate on the lines
>within the range that also match the pattern.       -- Darren

Or:
:10,20s/\(^#[iut]\)55/\171/

-- 
Alex Martelli - CAD.LAB s.p.a., v. Stalingrado 45, Bologna, Italia
Email: (work:) staff@cadlab.sublink.org, (home:) alex@am.sublink.org
Phone: (work:) ++39 (51) 371099, (home:) ++39 (51) 250434; 
Fax: ++39 (51) 366964 (work only; any time of day or night).