retorquere / zotero-better-bibtex

Make Zotero effective for us LaTeX holdouts
https://retorque.re/zotero-better-bibtex/
MIT License
5.35k stars 288 forks source link

Split subtitle from book title in collection #2220

Closed daaaaaaaaaniel closed 2 years ago

daaaaaaaaaniel commented 2 years ago

Support log: NPJ6NYB6-refs-euc

Zotero does not have a separate field for subtitles. Space-semicolon-space has been the recommended delimiter in the past, as discussed in other threads on the zotero forums[1]. I've tried addressing this missing feature in various ways ie. container-title-short: and/or tex.subtitle: in the Extras field. But using a postscript to automate it seems like the least laborious route.

A similar question was asked here over a year ago, and the postscript below was provided as the solution. I tested it today and confirmed that it works without issue for splitting a subtitle from a title.

if (Translator.BetterBibLaTeX && reference.has.title) {
  const titles = reference.has.title.value.match(/(.+?)([?:;])(.*)/)
  if (titles) {
    let title = titles[1] + (titles[2] === '?' ? '?' : '')
    reference.add({ name: 'title', value: title })
    reference.add({ name: 'subtitle', value: titles[3].trim() })
  }
}

Originally posted by @retorquere in https://github.com/retorquere/zotero-better-bibtex/issues/1759#issuecomment-798949707

However, I tried tweaking it slightly so that it would operate in the same manner on the booktitle container field for book sections in addition to the section title.

if (Translator.BetterTeX) {
  // BROKEN - Split long Book Title into Book Title, Book Subtitle
  // this is the same as the above code block, but i swapped 'title' for 'booktitle'
  // I tried using publicationTitle, bookTitle, and booktitle, but none of them worked…
  if (reference.has.booktitle) {
    const booktitles = reference.booktitle.value.match(/(.+?)([?:;])(.*)/)
    if (booktitles) {
      let booktitle = booktitles[1] + (booktitles[2] === '?' ? '?' : '')
      reference.add({ name: 'booktitle', value: booktitle })
      reference.add({ name: 'booksubtitle', value: booktitles[3].trim() })
    }
  }
  // Split long Title into Title, Subtitle
  if (reference.has.title) {
  // This part is almost exactly the same as the original solution. I've made some improvements.
  // The original script split at '?', which was a mistake in some titles with quotes, ie.
  // "What’s Happened to the People?" Gentrification and Racial Segregation in Brooklyn
    const titles = reference.has.title.value.match(/(.+?)([?:;]"?)(.*)/)
    if (titles) {
      if (titles[2] === '?' ){
        titles[2] = '?'
      } else if (titles[2] === '?"' ){
        titles[2] === '?"'
      } else {
        titles[2] = ''
      }
      let title = titles[1] + titles[2]
      // Authors who use parentesis in their titles break all sorts of conventions. Don't even bother seriously parsing.
      if (title.match(/\((?!.*\))/) ) {
        title = item.title
        titles[3] = ''
      }
      reference.add({ name: 'title', value: title })
      reference.add({ name: 'subtitle', value: titles[3].trim() })
    }
  }
}

I can't figure out how to adapt this postscript so that it works for titles and booktitles.

retorquere commented 2 years ago

Line 6 above is missing a .has, but this should work too:

if (Translator.BetterTeX) {
  function split(title) {
    const m = (title || '').match(/(.+?)([?]"|[?:;])(.*)/)
    return m ? { title: m[1], sub: m[2].trim() } : null
  }
  let title

  if (title = split(reference.has.booktitle && reference.has.booktitle.value)) {
    reference.add({ name: 'booktitle', value: title.title })
    reference.add({ name: 'booksubtitle', value: title.sub })
  }

  // Authors who use parentesis in their titles break all sorts of conventions. Don't even bother seriously parsing.
  if ((title = split(reference.has.title && reference.has.title.value)) && !title.title.match(/\((?!.*\))/)) {
    reference.add({ name: 'title', value: title.title })
    reference.add({ name: 'subtitle', value: title.sub })
  }
}
daaaaaaaaaniel commented 2 years ago

@retorquere Awesome!! I made one minor fix to your suggestion.

Line 4 should use m[3] instead of m[2]. Your version sets the (book)subtitle to nothing more than a semicolon for most items. Furthermore, I tweaked the title value on that same line so that titles ending in "?" retain the "?". With these adjustments, line 4 reads:

    return m ? { title: m[1] + m[2].replace(RegExp("\:"), "").trim(), sub: m[3].trim() } : null

And it seems to run perfectly! Thank you!!!

github-actions[bot] commented 2 years ago

Thanks for the feedback; there's no way you could have known, but @retorquere prefers to keep bugreports/enhancements open as a reminder to merge the changes into a new release.