summaryrefslogtreecommitdiff
path: root/internal/bible/ofref.go
blob: 8a723423e2bebdda55b4e3f7f9b4c683d299d716 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
package bible

import (
	"regexp"
	"strconv"
	"strings"

	"github.com/lukaszkasprzak/lectio/internal/psalter"
)

var (
	// ofCiteRe splits an English-canonical citation into book, chapter and the
	// verse tail: "2 Samuel 6:12b-15,17-19" -> ("2 Samuel", "6", "12b-15,17-19").
	// The book is non-greedy so a leading ordinal ("2 Samuel") stays with it.
	ofCiteRe = regexp.MustCompile(`^(.*?)\s+(\d+):(.+)$`)
	// ofVerseLetterRe drops sub-verse part letters so lookups resolve at whole
	// verses: "12b" -> "12", "3ab" -> "3", "3cd" -> "3".
	ofVerseLetterRe = regexp.MustCompile(`(\d)[a-z]+`)
)

// normalizeOFVerses rewrites a citation's verse tail into the shape
// bible.Lookup parses: cross-chapter semicolons become commas, ranges use a
// plain hyphen, sub-verse letters are dropped, and spaces are removed.
func normalizeOFVerses(tail string) string {
	tail = strings.ReplaceAll(tail, ";", ",")
	tail = dashRe.ReplaceAllString(tail, "-")
	tail = ofVerseLetterRe.ReplaceAllString(tail, "$1")
	tail = strings.ReplaceAll(tail, " ", "")
	return tail
}

// OFRef turns an English-canonical Ordinary Form citation (lectio's authored
// form) into a bible.Lookup-ready reference for the target corpus's Psalter.
//
// Every citation's verse tail is normalized (see normalizeOFVerses). Only the
// Psalms differ between Psalters, so their chapter/verse is additionally
// renumbered:
//
//   - "vulgate" (vul/grb/wuj): shift the Hebrew chapter to its Vulgate
//     equivalent (Ps 27 -> 26, Ps 147 -> 146). Verse numbers are kept, so the
//     rare intra-psalm verse-boundary shifts are not corrected here.
//   - "drb": the Douay-Rheims corpus keeps modern (Hebrew) chapter numbers, so
//     the chapter is kept; only the DRB title-fold verse shift applies (see
//     psalter.DrbVerse).
//   - "hebrew" / anything else: already in the corpus's numbering.
//
// A citation OFRef cannot parse (no "chapter:verse") is returned unchanged for
// bible.Lookup to accept or reject.
func OFRef(citation, system string) string {
	m := ofCiteRe.FindStringSubmatch(citation)
	if m == nil {
		return citation
	}
	book, chap, verses := m[1], m[2], normalizeOFVerses(m[3])

	if book == "Psalms" {
		heb, err := strconv.Atoi(chap)
		if err == nil {
			switch system {
			case "vulgate":
				chap = strconv.Itoa(psalter.HebrewToVulgateChapter(heb))
			case "drb":
				verses = digitsRe.ReplaceAllStringFunc(verses, func(s string) string {
					n, _ := strconv.Atoi(s)
					return strconv.Itoa(psalter.DrbVerse(heb, n))
				})
			}
		}
	}
	return book + " " + chap + ":" + verses
}