vim: how to substitute ^H into an delete action

64 views
Skip to first unread message

ping

unread,
Aug 27, 2012, 9:53:51 AM8/27/12
to vim-use Mailingliste
One question puzzles me for a long time and I'm not sure if it can be
easily solved in vim...

say I have some log file, if I copy & paste into this email, it will
look like this:

PRVDRI-VFTTP-32:vol#show term len 50
PRVDRI-VFTTP-32:vol#show subsc
PRVDRI-VFTTP-32:vol#show subscribers

actually in my vim terminal, it displays following literally


5057 ^MPRVDRI-VFTTP-32:vol#show ^H^H^H^H^H ^H^H^H^H^Hterm len 50


5058 ^MPRVDRI-VFTTP-32:vol#show subsc
5059 ^MPRVDRI-VFTTP-32:vol#show subscribers

apparently someone input something wrong in his terminal emulator,
delete them back with backspace, then input some new command into the
text. so the logging program record all sequences without converting the
^H into "delete backward on charactor" action.

is there a way to substitute, say all ^H , into an action that delete
backward one charactor?

b.t.w the ^H here is ONE special charactor, not ^ and H

I have similiar issues for some other special charactors (^G, ^M, etc).

Ben Fritz

unread,
Aug 27, 2012, 10:59:37 AM8/27/12
to vim...@googlegroups.com
I had to do this with ^H once, I think I solved it with something like:

:g/^H/while getline('.') =~ '[^^H]^H' | s/[^^H]^H//g | endwhile

There are probably better ways to do it.

ping

unread,
Aug 27, 2012, 12:04:37 PM8/27/12
to vim...@googlegroups.com, Ben Fritz
can even do that???
it work! this is amaaazing!!!
another example of "power of G"...

thanks!

regards
ping

Andy Wokula

unread,
Aug 27, 2012, 12:22:38 PM8/27/12
to vim...@googlegroups.com
Am 27.08.2012 15:53, schrieb ping:
> One question puzzles me for a long time and I'm not sure if it can be
> easily solved in vim...

Just ask ... there is a nice little trick you can use (works even better
than a :substitute), see below.
:h i_CTRL-R

:setl tw=0
:g/\b/exec "normal! 0\"rC\<C-R>r"

Control keys are processed as if typed in Vim, e.g. ^G expects another
character ... you should probably first remove unwanted chars.

--
Andy

ping

unread,
Aug 27, 2012, 4:37:51 PM8/27/12
to vim...@googlegroups.com, Andy Wokula
Thanks Andy!
this looks a clever trick...it makes use of i_ctrl-R implementation..
looks like special charactors will be simply skipped from i_ctrl-R...


I found :@" seems to have the same (similar) issue? or not, not sure...
but I copied Ben's line into a register and tried :@", it doesn't work,
looks I have to literally input them under Ex...

Anyway as a summary, from what I tested, Ben's method:
:g//while getline('.') =~ '[^^H]^H' | s/[^^H]^H//g | endwhile

work much better. it equivalently convert ^H into a backspace action,
which is really nice, at least for me.

Andy Wokula

unread,
Aug 27, 2012, 5:15:44 PM8/27/12
to vim...@googlegroups.com, ping
Am 27.08.2012 22:37, schrieb ping:
> Thanks Andy!
> this looks a clever trick...it makes use of i_ctrl-R implementation..
> looks like special charactors will be simply skipped from i_ctrl-R...

No, special characters are *applied*, as if typed (just try it out).

--
Andy

Ben Fritz

unread,
Aug 27, 2012, 11:15:49 PM8/27/12
to vim...@googlegroups.com, Andy Wokula
On Monday, August 27, 2012 3:38:00 PM UTC-5, ping wrote:
> I found :@" seems to have the same (similar) issue? or not, not sure...
>
> but I copied Ben's line into a register and tried :@", it doesn't work,
>
> looks I have to literally input them under Ex...
>

Yeah...I suppose I should have mentioned that.

I don't know of a way (aside from sending a .txt file attachment) to send actual literal CTRL-H characters, so I just typed ^ and then H. Which obviously does something very different than a real ^H character.

ping

unread,
Aug 28, 2012, 10:38:13 AM8/28/12
to vim...@googlegroups.com, Ben Fritz, Andy Wokula
Ben, that part I understood,
what I mentioned is, even after I correctly typed in c-h (via c-v c-h in
vim), and I yank it with yy, but again :@" (execute the register ")
doesn't work. I'm not sure it's my issue (mostly should be) or vim's
current implementation...

Ben Fritz

unread,
Aug 28, 2012, 11:07:44 AM8/28/12
to vim...@googlegroups.com, Ben Fritz, Andy Wokula
Ok, yes I see that now, and I can reproduce. I tried entering this text in a new buffer (with ^H meaning a literal CTRL+H character):

g/^H/while getline('.') =~ '[^^H]^H' | s/[^^H]^H//g | endwhile

Yanking with yy or with 0y$ and running :@0 gives:

E33: No previous substitute regular expression
E476: Invalid command

To debug, I did:

:debug @0

and saw that the command actually being executed is:

g/while getline('.') =~ '[' | s/[//g | endwhile

It looks like executing :@0 is for some reason interpreting the characters as if typed. I don't know if this is intentional or not, but it's easy enough to fix by inserting literal ^V characters before the ^H characters before yanking.

I would expect this to be necessary to run a macro with @0 in normal mode, because those ^V characters will be in the macro if you record it. But I wasn't expecting it in the ex-mode command.

Especially, since :@: works on this command, and :reg : shows the contents as NOT including any ^V characters.

John Little

unread,
Aug 29, 2012, 12:25:41 AM8/29/12
to vim...@googlegroups.com
What's wrong with

%s/[^\b]\b//g

repeated till it finds nothing? Or do it once to check it out, then get vim to repeat it:

:while 1 | %s///g | endwhile

Regards, John

Ben Fritz

unread,
Aug 29, 2012, 10:13:00 AM8/29/12
to vim...@googlegroups.com
Nothing wrong with that. Actually it's pretty clever to have an infinite loop ended only by the "no matches" error when you've removed them all. I was avoiding the error by using a :g and repeating a substitute on each line until there were no longer any matches with an explicit check. Your way is not as clear at first glance but almost certainly faster and more efficient. I've got to remember to take advantage of the "error-ends-X" behavior in mappings, macros, and loops more often.

Using \b instead of a literal ^H also removes the problem of yanking and executing the command. I didn't know about \b (since I almost never have text with a literal backspace character). Thanks for sharing!

ping

unread,
Aug 30, 2012, 3:15:49 PM8/30/12
to vim...@googlegroups.com, Ben Fritz
really nice, all concern removed now.

so to conclude: this is the best practice so far for use in vimscripting:

.w/o warning
----
:g/[\b]/while getline('.') =~ '[^\b]\b' | s/[^\b]\b//g | endwhile
----

or
.w/ (harmless) warning
----
:while 1 | %s/[^\b]\b//g | endwhile
----

I tested both.
Reply all
Reply to author
Forward
0 new messages