Assuming your initial text looks like this:
@article{some name,
title={Can quantum-mechanical description of physical reality be considered complete?},
author={Einstein, Albert and Podolsky, Boris and Rosen, Nathan},
journal={Physical review},
volume={47},
number={10},
pages={777},
year={1935},
publisher={APS}
}
Then you could try this substitution command:
%s/^\s*@article{\zs.*\ze,/\=substitute(matchstr(getline(search('^\s*title=', 'nW')), '{\zs.\{-}\ze}'), '\(\k\)\k*\%(\k\@!.\)*', '\1', 'g')/
If you execute it in your file, it should look for all the lines starting with @article{
and replace the following name with the first letter of each word on the next line beginning with title=
.
IOW, it should perform the following substitution:
@article{some name,
title={Can quantum-mechanical description of physical reality be considered complete?},
→
@article{Cqmdoprbcc,
title={Can quantum-mechanical description of physical reality be considered complete?},
The syntax of this substitution is:
%s/pat/\=expr/
│ │ ├┘│
│ │ │ └ the expression to be evaluated
│ │ │
│ │ └ replace it by the evaluation of the following expression
│ │ (see `:h :s\=`)
│ │
│ └ every time you find a first occurrence of the pattern
│ described by the string 'pat' on a line
│
└ operate on all the lines of the file
Here the pattern is:
^\s*@article{\zs.*\ze,
│├┘│├───────┘├─┘││├─┘│
││ ││ │ │││ └ the text `,`
││ ││ │ │││
││ ││ │ ││└ look for everything I will describe afterwards,
││ ││ │ ││ but don't replace it when doing the substitution (`:h \ze`)
││ ││ │ ││
││ ││ │ │└ as many as possible
││ ││ │ │
││ ││ │ └ any character (from the old entry name) (`:h /.`)
││ ││ │
││ ││ └ look for everything I've described thus far,
││ ││ but don't replace it when doing the substitution (`:h /\zs`)
││ ││
││ │└ the text `@article{`
││ │
││ └ as many as possible (`:h /*`)
││
│└ a whitespace (`:h /\s`)
│
└ a beginning of line (see `:h /^`)
And the expression is:
substitute(matchstr(getline(search('^\s*title=', 'nW')), '{\zs.\{-}\ze}'), '\(\k\)\k*\%(\k\@!.\)*', '\1', 'g')
The evaluation of search('^\s*title=', 'nW')
is the numerical address of the next line (relative to where :s
command is performing a substitution at the moment) described by the pattern ^\s*title=
. IOW, it's the address of the next line beginning with title=
. Let's call it S
.
During the evaluation of S
, the cursor won't move because of the n
flag passed in the 2nd argument (:h search()
).
Using the S
symbol, the expression can be re-written like this:
substitute(matchstr(getline(S), '{\zs.\{-}\ze}'), '\(\k\)\k*\%(\k\@!.\)*', '\1', 'g')
The evaluation of getline(S)
is a string, matching the contents of the next line beginning with title=
(:h getline()
).
Let's call it G
.
Using the G
symbol, the expression can be re-written like this:
substitute(matchstr(G, '{\zs.\{-}\ze}'), '\(\k\)\k*\%(\k\@!.\)*', '\1', 'g')
The evaluation of matchstr(G, '{\zs.\{-}\ze}')
is a substring of the previous string. Let's call it M
. More specifically, it's the part between 2 CONSECUTIVE (because you used the LAZY quantifier \{-}
, instead of the greedy *
; see :h /\{-
) curly brackets.
Using the M
symbol, the expression can be re-written like this:
substitute(M, '\(\k\)\k*\%(\k\@!.\)*', '\1', 'g')
The evaluation of this last expression is what you want, i.e. the first letter of each word in your original title.
You could re-write it like this:
substitute(M, pat, rep, 'g')
Where pat
is a pattern that substitute()
has to look for, here \(\k\)\k*\%(\k\@!.\)*
, and rep
is the replacement string, here \1
.
The pattern can be broken down like this:
\(\k\)\k*\%(\k\@!.\)*
├────┘├─┘├──────────┘
│ │ └ a sequence of NON-keyword characters, as long as possible (see `:h /\@!`)
│ │
│ └ a sequence of other keyword characters, as long as possible
│
└ look for a keyword character (`:h /\k`), and remember it (`:h /\(`)
The replacement string is special, and not a literal string. \1
refers to the first capturing group in your pattern, which here is the first keyword character of every word in your original title (:h /\1
).
You could also turn it into a custom command (:SetEntryName
):
com! -bar -range=% SetEntryName call s:set_entry_name(<line1>, <line2>)
fu! s:set_entry_name(line1, line2) abort
let range = a:line1.','.a:line2
exe range.'s/^\s*@article{\zs.*\ze,/\=s:get_entry_name()/'
endfu
fu! s:get_entry_name() abort
let entry = getline(search('^\s*title=', 'nW'))
let entry = matchstr(entry, '{\zs.\{-}\ze}')
let entry = substitute(entry, '\(\k\)\k*\%(\k\@!.\)*', '\1', 'g')
return entry
endfu
The command accepts a range, thus works on a visual selection.