2

In Python, I am trying to update my code from typed dict to dataclass. Language is just indicated as a reference, it is a pure Vim question.

I need to replace my_params["some_property"] with my_params.some_property

I have some difficulty replacing [".

How can I replace everything at once?

Lionel Hamayon
  • 233
  • 2
  • 8

3 Answers3

3

Since replacing everything at once is likely to accidentally get some wrong things, I would make sure to add the confirm flag, or be a bit cleverer: we’ll use the surround plugin and a macro to step through the file and make the changes.

  1. /\[": search for a pattern that should find all the things you need to change but may find extras. Press n until you’re on a match that needs changed.
  2. qqds[ds"i.<esc>q: record a macro that deletes square brackets, quotes, and inserts a dot.
  3. Press n/N to find places to edit and @q (the first time)/@@ (subsequent times) to make the change.
D. Ben Knoble
  • 26,070
  • 3
  • 29
  • 65
2

New version from @b-layer

:%s/\v\["([^"]+)"]/.\1/gc
  • %s targets the whole file
  • \v is the very magic modifier
  • \[" matches ["
  • ([^"]"+) represents the capture group for some_property, which [^"] ends at the next double quotes. + makes it at least one character.
  • \1 references the capture group in the replacement section
  • \g enables to replace for more than one occurrence per line and c asks for confirmation

Previous version:

I could perform the replacement executing the following command:

:%s/\v(\[")(.*)("\])/.\2/gc

where:

  • \v is the very magic modifier,
  • (\[")and ("\]) the capture groups 1 and 3 for the brackets and double quotes
  • (.*) the capture group 2, which is then referenced with \2 in the replacement section.
Lionel Hamayon
  • 233
  • 2
  • 8
  • 2
    If you're not using them in the replacement you shouldn't need capture groups 1 and 3. Also, ] doesn't need to be escaped. Finally, .* is pretty greedy so it's usually safer to use a "not the next thing I want to match" pattern instead...in this case [^"]*. So :%s/\v\["([^"]*)"]/.\1/gc – B Layer Aug 17 '21 at 09:36
  • 1
    (And it really should be a + rather than a * since my_params[""] isn't valid...but that's a small detail. :) – B Layer Aug 17 '21 at 09:44
  • 1
    thanks for the very thorough review :) – Lionel Hamayon Aug 19 '21 at 07:24
0

Given I sometime use single quotes and other times doubles quotes, here is another variation on B-Layer :substitute command that supports both, plus the reverse operation.

In order to remember the names, I've wrapped the two actions into commands.

command! -range=1
      \ ToAttribute <line1>,<line2>s/\v\[(["'])([^"']+)\1]/.\2/gc
command! -range=1 -nargs=? -complete=customlist,s:compl_to_dict
      \ ToDict      call s:to_dict(<f-args>)

" Internal support functions for :ToDict function! s:to_dict(...) range abort let quote = get(a:, 1, "'") exe printf('%s,%ss/\v.(\k+)/[%s\1%s]/gc', a:firstline, a:lastline, quote, quote) endfunction

function! s:compl_to_dict(...) abort return ['"', "'"] endfunction

Luc Hermitte
  • 17,351
  • 1
  • 33
  • 49