We help IT Professionals succeed at work.

Vi / Vim single optional character in a regular expression

I'm doing a search and replace so I want to add a character return after all the paragraph tags so that the code is easier to deal with in vim.

.,$s/<p>/&\r/gc
but I also want it to do this for the closing tags as well.  I heard the ? is sometimes used for a single optional character but I still haven't figured out how to find deal with a single optional character.

I tried this:
.,$s/<?p>/&\r/gc
and this
.,$s/<.?p>/&\r/gc
Comment
Watch Question

CERTIFIED EXPERT
Most Valuable Expert 2011
Top Expert 2015

Commented:
The question mark needs to follow something. When it does, it means zero-or-one of the thing it follows. In your example, <?, it means zero-or-one less-than character. Your second option should work because the dot means any character, and the question mark following it alters the meaning to zero-or-one of any character. Myself, I would prefer /?, because you already know what character you are expecting--why not use it. The full pattern would then be:

.,$s/<\/?p>/&\r/gc

Open in new window


Note that I had to escape (using a backslash) the forward slash for the close tag because your pattern delimiters are forward slashes. If you don't do this, then the regex engine thinks the slash after the less-than is the ending delimiter for the pattern.
I think your problem is that you need to replace a "/" character but you are using that as the search delimiter.  

You can replace the "/" delimiter with "?", so
s/old/new/gc is the same as
s?old?new?gc

That means you can now use
.,$s?</p>/&\r?gc

Is that what you are trying to do or did I get that wrong?
CERTIFIED EXPERT
Most Valuable Expert 2011
Top Expert 2015

Commented:
This is an excellent site for learning regex:  http://www.regular-expressions.info/tutorial.html  For your particular issue, the section "Optional Items" would be of particular interest.
I didn't get that quite right - I meant it should now be:
:.,$s?</p>?&\r?gc
CERTIFIED EXPERT
Most Valuable Expert 2011
Top Expert 2015

Commented:
@Martin_J_Parker
I meant it should now be
The question mark needs to come after the slash, not the closing bracket  = )
HonorGodSoftware Engineer
CERTIFIED EXPERT

Commented:
Do you want to replace the <p> and </p> tags with a carriage return (i.e., \r),
or do you want to add a carriage return after the tag?

To answer the original question, a single optional character is often represented by "." in vi.
If you have 3 lines
1 ax
2 bx
3 cx
then
:1,$s/.x/y&
will end up with
1 yax
2 ybx
3 ycx
HonorGodSoftware Engineer
CERTIFIED EXPERT

Commented:
Side note:

:1,$

is identical to:

:%

So this:

:%s/.x/y&

is the same as this:

:1,$s/.x/y&

Author

Commented:
I just wanted to add a carriage return after both the open and closing paragraph tags.  How do I select the open tag and the close tag with one expression?  %s/<p>/ selects all the open tags
and %s/<\/p>/ selects all the closing tags.  But I want to select both of them at once.  I want to convey to vim that the forward slash in the tag is optional.  If i used <.*p> it will select the whole line up to the closing tag.  I want it to know that there is only one optional character.
CERTIFIED EXPERT
Most Valuable Expert 2011
Top Expert 2015
Commented:
a single optional character is often represented by "."
The word "optional" in that statement makes the statement inaccurate. Strike that word, and the statement holds.

Try this out:

:1,$ s#</*p>#&\r#gc

Open in new window

Author

Commented:
This one is the closest so thanks.  I probably didn't phrase it well enough.  In fact that was my real problem: how to phrase the question.

Although /* finds 0 or more / which is fine for tags since they only have one slash but I've been wondering for a long time how to find 0 or 1 character.  Although I hadn't phrased it that way before. When I did  I found this page:

http://vimdoc.sourceforge.net/htmldoc/pattern.html

and found

 \=

and

\?

both match 0 or 1 character.  So that ? was almost correct I just forgot to try adding a  backslash before it.

0 or 1 backslash:
:.,$s#</\?p>#&\r#gc   (i didn't know you could use # or ? to delimit the sections)
:.,$s/<\/\?p>/&\r/gc  
:.,$s?<\/\=p>?&\r?gc  
0 or 1 any character:
:.,$s#<.\?p>#&\r#gc
CERTIFIED EXPERT
Most Valuable Expert 2011
Top Expert 2015

Commented:
I would have preferred to give you the zero-or-one approach, but when I was looking through vi documentation, it didn't seem like it was available. Nonetheless, glad you found your solution  = )