diff options
Diffstat (limited to 'internal/bible')
| -rw-r--r-- | internal/bible/ref.go | 78 | ||||
| -rw-r--r-- | internal/bible/ref_test.go | 31 |
2 files changed, 109 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 +} diff --git a/internal/bible/ref_test.go b/internal/bible/ref_test.go new file mode 100644 index 0000000..3a661ad --- /dev/null +++ b/internal/bible/ref_test.go @@ -0,0 +1,31 @@ +package bible + +import "testing" + +func TestSplitRef(t *testing.T) { + got := SplitRef("John 20:1,11-18") + want := []string{"John 20:1", "John 20:11-18"} + if len(got) != 2 || got[0] != want[0] || got[1] != want[1] { + t.Fatalf("SplitRef mixed = %v want %v", got, want) + } + if g := SplitRef("Mat 7:1-5"); len(g) != 1 || g[0] != "Mat 7:1-5" { + t.Errorf("SplitRef contiguous = %v", g) + } +} + +func TestLookup(t *testing.T) { + vs, missing := Lookup("wuj", "John 20:1,11-18") + if len(missing) != 0 { + t.Fatalf("missing = %v", missing) + } + if len(vs) == 0 || vs[0].Verse != 1 { + t.Fatalf("first verse = %+v", vs) + } + last := vs[len(vs)-1] + if last.Verse != 18 { + t.Errorf("last verse = %d want 18", last.Verse) + } + if _, m := Lookup("vul", "Wisdom 3:1"); len(m) == 0 { + t.Error("vul lacks Wisdom; expected a missing entry") + } +} |
