I want to annotate words /sentences for a "named entity recognition" purpose; inside a text file, I want to annotating words or sentences with this format [pattern](label):

[a word where the cursor is or a selected sentence, a span](entity_name)

Suppose I have this text file:

  # untagged.yaml
  - intent: body_temperature_data
    examples: |
      - il termometro misura 36.3 gradi
      - 36.9
      - 35,9
      - la temperatura è di 36 e 7 gradi
      - 36 , 8

I want by example to tag decimal numbers assigning the entity body_temperature to each of them, transforming the original file in this one:

  # after_tagging.yaml
  - intent: body_temperature_data
    examples: |
      - il termometro misura [36.3](body_temperature) gradi
      - [36.9](body_temperature)
      - temperatura: [35,9](body_temperature)
      - la temperatura è di [36 e 7](body_temperature) gradi
      - [36 , 8](body_temperature)

What I need is a vim way to quickly substitute this line:

  - il termometro misura 36.3 gradi

in this line:

  - il termometro misura [36.3](body_temperature) gradi

Now, suppose I'm with cursor inside a word (a number in fact):


I want to substitute the (selected) word or sentence, with a keyboard shortcut in


So the original pattern 36.3 would be "decorated" with [pattern](label)

I know the basic substitute command:


and in this special case I want to do something like


But i do not know the syntax to make this replacement, maybe something like this (still not working):

  • let assume body_temperature is in a short list of options (label_1, label_2, label_N) maybe stored in a vimscript variable I can assign.
  • I would like to trigger the substitution with a keyboard shortcut (e.g. F1 key).

How can I do that?

BTW, that's part of the bigger problem here detailed: Vim editor entities tagging/annotation tool


1 Answer 1


Normal mode

with the :substitute command.

nnoremap <leader>t :s/\%#\<<c-r><c-a>\>/[&]()/<cr>f(a

The trick is to use <c-r><c-a> which will insert the :h <cWORD> under the cursor, i.e non-whitespace characters. <c-r><c-w> would insert the <cword>, which respects :h 'iskeyword', and would therefore (with default values) not contain decimals in floating numbers.

:h \%# start the match at the cursor position, so only the current occurrence of the pattern matches. This means the mapping will fail if the cursor is not on the first character of the word.

:h \<and \> match the beginning and end of a word. It's probably unecessary here.

Finally, the & in the string part represents the matched pattern, <cr> launches the command.

f(a places the cursor in insert mode between parentheses.

"simple" way

nnoremap <leader>t ciW[<c-o>P]()<left>

ciw]: delete the under the cursor and insert [.

<c-o>P: paste what was just deleted before the cursor

](): insert the rest of the decoration

<left>: go between parenthesis

Visual mode

vnoremap <leader>t :s/\%V.*\%V./[&]()/<cr>f(a

The difference is the match pattern: \%V.*\%V. matches the visual selection (:h \%V).

Setting mappings for each label

This script creates a mapping <leader>tX for each 'label' in the 's:labels' variable, X being a number. printf is a convenient way to pass a string to the execute command.

let s:labels = ["label1", "label2", "label3"]
for i in range(len(s:labels))
  exe printf("vnoremap <leader>t%d :s/\\%%V.*\\%%V./[&](%s)/<cr>n:nohl<cr>f)", i+1, s:labels[i])
  exe printf("nnoremap <leader>t%d ciW[<c-o>P](%s)<esc>", i+1, s:labels[i])

n:nohl<cr>f) tries to place the cursor after the label. It will fail if a ) is in the pattern.

  • you are a vim-genius! I needed much time to read and understand your suggestions. Chapeau and thanks for great explanations. A small variant of your "simple" mode, when you want to annotate next two words from the current cursor: :nnoremap <F2> c2W[<c-o>P]()<left> . A lot to learn myself. To be continued... Commented Mar 30, 2022 at 15:36
  • I usually try to avoid numbers in this context in favor of operators for consistency. Thanks for your compliment, I appreciate -- however, I don't think I deserve being called a 'Vim genius' (yet). There's many of them on this forum, from whom I learned a few skills that helped me write this answer. Enjoy your vim journey!
    – Biggybi
    Commented Mar 30, 2022 at 18:54
  • Thx! BTW, your multi-label "setting mappings" inspired me to code the following idea: I want to realize a command like :MyPluginSetFunctionKeyLabel F2 label2. The command will do exe printf("vnoremap <F2> :s...) in that way user can dynamically/on-the fly set-up a single function key to do the visual/byword substitution. I I'll publish the plugin I'll acknowledge you. Maybe the plugin will be complementary to github.com/solyarisoftware/Highlight.vim Commented Mar 31, 2022 at 9:45
  • 1
    mentioned you @Biggybi in acknowledgements section of the plugin I just made (super draft), inspired by your examples: github.com/solyarisoftware/nesa.vim Commented Apr 1, 2022 at 14:36
  • 1
    ERRATA CORRIGE: the name of plugin I made, inspired by @biggybi examples (thanks again) is: github.com/solyarisoftware/nera.vim Commented Sep 28, 2022 at 8:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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