aboutsummaryrefslogtreecommitdiff
path: root/internal/bible/ref.go
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-07-23 12:51:41 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-07-23 12:51:41 +0200
commit0fd209b654b057efa281f86d7bfd5043a12ce407 (patch)
treed51224a3ee16b34dbc77eff836ca7cf95dfb1fee /internal/bible/ref.go
parent998e0d5bb2aa4412ca05d28f27592ae54727e2ba (diff)
downloadlectio-0fd209b654b057efa281f86d7bfd5043a12ce407.tar.gz
lectio-0fd209b654b057efa281f86d7bfd5043a12ce407.zip
bible: reference grammar + Lookup
Diffstat (limited to 'internal/bible/ref.go')
-rw-r--r--internal/bible/ref.go78
1 files changed, 78 insertions, 0 deletions
diff --git a/internal/bible/ref.go b/internal/bible/ref.go
new file mode 100644
index 0000000..c88e722
--- /dev/null
+++ b/internal/bible/ref.go
@@ -0,0 +1,78 @@
+package bible
+
+import (
+ "regexp"
+ "strconv"
+ "strings"
+)
+
+var refRe = regexp.MustCompile(`^(.*?)\s+(\d+):(.+)$`)
+
+// SplitRef splits a ref whose verse list mixes single verses and ranges into
+// one ref per group (the kjv tools reject a mixed list in a single query).
+func SplitRef(ref string) []string {
+ m := refRe.FindStringSubmatch(ref)
+ if m == nil {
+ return []string{ref}
+ }
+ book, chap, verses := m[1], m[2], m[3]
+ if !strings.Contains(verses, ",") {
+ return []string{ref}
+ }
+ var out []string
+ for _, g := range strings.Split(verses, ",") {
+ g = strings.TrimSpace(g)
+ if g == "" {
+ continue
+ }
+ if strings.Contains(g, ":") {
+ out = append(out, book+" "+g)
+ } else {
+ out = append(out, book+" "+chap+":"+g)
+ }
+ }
+ return out
+}
+
+// Lookup resolves an English-style reference against a version, returning the
+// matched verses (in order) and the sub-refs the corpus had no entry for.
+func Lookup(version, ref string) ([]Verse, []string) {
+ var verses []Verse
+ var missing []string
+ for _, part := range SplitRef(ref) {
+ m := refRe.FindStringSubmatch(part)
+ if m == nil {
+ missing = append(missing, part)
+ continue
+ }
+ book, ok := ResolveBook(m[1])
+ if !ok {
+ missing = append(missing, part)
+ continue
+ }
+ chap, _ := strconv.Atoi(m[2])
+ from, to := verseRange(m[3])
+ found := false
+ for _, v := range Verses(version, book, chap) {
+ if v.Verse >= from && v.Verse <= to {
+ verses = append(verses, v)
+ found = true
+ }
+ }
+ if !found {
+ missing = append(missing, part)
+ }
+ }
+ return verses, missing
+}
+
+func verseRange(s string) (int, int) {
+ s = strings.TrimSpace(s)
+ if i := strings.IndexAny(s, "-–—"); i >= 0 {
+ from, _ := strconv.Atoi(strings.TrimSpace(s[:i]))
+ to, _ := strconv.Atoi(strings.TrimSpace(s[i+1:]))
+ return from, to
+ }
+ n, _ := strconv.Atoi(s)
+ return n, n
+}