3

I am trying to map q in vi (not Vim) to find a pattern and replace it with newline:

Name1 Name2 Name3 Name4

to

Name1
Name2
Name3
Name4

When I try ([Ctrl-V] and [Enter] are actual keystrokes)

:map q :%s/Name. /[Ctrl-V][Enter]&/g[Ctrl-V][Enter]

It fails, since it considers the first [Ctrl-V][Enter] itself as enter. I don't know how to make it a literal newline.

I have read Carriage return vs newline in vim and it suggests using \r for newline while replacing. This seems only to work in Vim and does not work under vi.

Please help.

3

This will be a bit convoluted, but, try:

:map q :%s/Name. /\^V^V^M&/g^M

Each ^x is produced by pressing CtrlVCtrlx, so the actual sequence here is:

  1. CtrlV CtrlV for the first ^V,
  2. CtrlV CtrlV for the second ^V,
  3. CtrlV Enter for the first ^M.
  4. And again for the last ^M.

From man ex:

Lines may be split by substituting new-line characters into them. The newline in repl must be escaped by preceding it with a '\'. Other metacharacters available in pat and repl are described below.

And from An Introduction to Display Editing with Vi:

You can use the map command from vi (typically in your EXINIT) with a command of the form:

:map lhs rhsCR

mapping lhs into rhs. There are restrictions: lhs should be one keystroke (either 1 character or one function key) since it must be entered within one second (unless notimeout is set, in which case you can type it as slowly as you wish, and vi will wait for you to finish it before it echoes anything). The lhs can be no longer than 10 characters, the rhs no longer than 100. To get a space, tab or newline into lhs or rhs you should escape them with a ^V. (It may be necessary to double the ^V if the map command is given inside vi, rather than in ex.) Spaces and tabs inside the rhs need not be escaped.

So:

  1. We need to prefix the newline given to :s with a \.
  2. If we were typing the command in vi, then we'd press CtrlV CtrlM to get the newline in the command. That means we have to make the mapping so that it would be as if we had pressed CtrlV CtrlM.
  3. We need CtrlV CtrlV just to get one ^V to the command. But we need two, so that it would be as if we'd typed CtrlV.

The reduction would be like this:

  1. ^V^V^V^V^V^M typed
  2. Which the map command will receive as ^V^V^M
  3. Which will be interpreted while executing the map as ^V^M
  4. To get a literal ^M.

After all that, the output still won't be what you wanted:

​
Name1
Name2
Name3 Name4

😭

  • 3
    Nice +1! To get the output desired by @Banavara, in the replacement part, maybe you could invert the order of the newline and the backreference to the whole pattern &: :map q :%s/Name. /&\^V^V^M/g^M – user9433424 Apr 30 '16 at 9:49
  • 1
    WOW...! Fantastic muru. I had to read 2/3 times to understand that. It works like charm. for the last part, * operator matching none or more occurance can be used as :map q :%s/Name. */\^V^V^M&/g^M (but it still inserts a newline at the top. I have another question regarding this, will post it as a different question. (The answer was so good, I created an account to comment! Thank you muru) – Banavara Apr 30 '16 at 11:43
  • @Banavara thanks. But see user9433424's comment above, I'd say that's correct. – muru Apr 30 '16 at 11:46
  • Thank you @user9433424, your solution works just as I specified. The reason for inserting newline before Name is that there are some other details after Name field and I wanted all records to be broken Name field, so that all details are on their own line. – Banavara Apr 30 '16 at 12:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.