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 }