command line - How to "reuse" a regex find and replace in Vim

17
2014-04
  • Richard Herron

    I have a plain text file with entries as

    firstAuthorLastName_titleFirstWord_YYYY
    

    that I change to

    firstAuthorLastNameYYYYtitleFirstWord
    

    with the following s// command in Vim.^[1]

    %s/\([a-z]\+\)_\([a-z]\+\)_\([0-9]\{4}\)/\1\3\2/g
    

    But I want to do this command over and over again. It seems that I should be able to do this with a Windows batch script and the -c flag to gvim.exe. But I can't get it to work.

    I have a Windows batch script with the following.

    gvim -c "%s/\([a-z]\+\)_\([a-z]\+\)_\([0-9]\{4}\)/\1\3\2/g" herron.bib
    

    But I get the message E486: Pattern not found: \([a-z]\+\)_\([a-z]\+\)_\([0-9]\{4}\). Is there a way to reuse/automate this s// command? I know that I can up arrow through my ex command history, but I'd like something a little more permanent and reliable.

    [^1] FWIW, this is a BibTeX .bib file that I export from Zotero. Further downstream I use vim-pandoc to write notes in markdown. The underscores make it a little more difficult to use the vim-pandoc "tidy" function, so I remove them. I update the .bib several times a week and re-export it from Zotero, so I also need to run this regex several times a week.

  • Answers
  • Ingo Karkat

    I don't see anything wrong, and apparently the pattern is correctly passed to Vim, so it should work :-(

    Alternatives

    Unless you really need special Vim capabilities, you're probably better off using non-interactive tools like sed, awk, or Perl / Python / Ruby / your favorite scripting language here.

    That said, you can use Vim non-interactively:

    Silent Batch Mode

    For very simple text processing (i.e. using Vim like an enhanced 'sed' or 'awk', maybe just benefitting from the enhanced regular expressions in a :substitute command), use Ex-mode.

    REM Windows
    call vim -N -u NONE -n -es -S "commands.ex" "filespec"
    

    Note: silent batch mode (:help -s-ex) messes up the Windows console, so you may have to do a cls to clean up after the Vim run.

    Vim alternatives

    Based on your description, it's not entirely clear whether you want full automation, or just easier recall. If you don't mind applying the command manually (but quickly) from within Vim, how about:

    a) a custom command

    :command! TidyNames %s/\([a-z]\+\)_\([a-z]\+\)_\([0-9]\{4}\)/\1\3\2/g
    

    b) a custom mapping

    :nnoremap <Leader>tn :%s/\([a-z]\+\)_\([a-z]\+\)_\([0-9]\{4}\)/\1\3\2/g<CR>
    

    Both of these can be placed into your ~/.vimrc, or (with <buffer> modifier) in a filetype-specific ~/.vim/after/ftplugin/tex.vim.


  • Related Question

    VIM Regex replacing words
  • Christian

    Which regex do I have to use in VIM to replace all words 'to' from a text with the word 'foo'? (I don't want to replace 'to' when it happens in a word like 'together').


  • Related Answers
  • John T

    this should work:

    :%s/\<to\>/foo/g
    

    Using \< and \> ensure that "to" will only be replaced if it is an entire word. \< matches the start of a word and \> the end. This way it won't turn your "tod" into "food" :)

  • James

    I'm sure there's a simpler way, but:

    :%s/\(\w\)to\(\w\)/\1foo\2/gc
    

    would do the trick

    EDIT: John T has posted the simpler way :D