1

I would like to copy the first letters of paper titles in a bib file and set that as entry name.
Example:

@article{Cqmdoprbcc,
  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}
}

Notice that the bibtex entry, Cqmdoprbcc, is the first letters of each word in the title.

I am clueless as how to do it and I was hoping I could learn from masters of vim here.

2

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.

  • Thank you very much. The entry name is not blank by default though. How do you suggest that I delete the entry to bring it to the format so I can apply your code? Thanks a lot – Ali Aug 24 '18 at 23:57
  • @Ali I edited the answer to support lines looking like this: @article{some name,. If the code doesn't work, knowing the exact form of the original text would help. – user938271 Aug 25 '18 at 0:04
  • Thanks a lot. It works like a charm. If you get a chance, would you mind explaining how it works? Especially the regex part. Thanks. – Ali Aug 25 '18 at 6:16
  • Hats off to you. You deserve 1000000 upvotes. Thank you very much. I learned a lot :) – Ali Aug 25 '18 at 22:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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