mirror of
https://git.pumpin.online/funkpower/catena.git
synced 2026-10-22 18:57:14 +00:00
citefind: chapter and verse is not a work in a bibliography
Found by putting a real model at the end of the chain: a page of notes from a theological book composed a prompt asking who wrote Matthew 4:17, and the model rightly answered nothing for all twenty-three entries. Those are scripture references, which is most of what the notes of such a book are, and they are now not references at all — no record, and no question put to anybody about them. A journal and its volume look similar on the page and are still read as what they are. Also: the stop that belonged to a marker no longer opens the entry after it.
This commit is contained in:
@@ -181,6 +181,11 @@ back. Nor does a run carrying a page reference or a semicolon count as one:
|
||||
that is two entries run together, or a reference to a work rather than the
|
||||
name of one.
|
||||
|
||||
**Take chapter and verse for a work.** `Matthew 4:17` and `Cf. Deuteronomy
|
||||
18:15-19; Isaiah 53` are scripture references, which is most of what the notes
|
||||
of a theological book are. Nobody is looking for the publisher of Galatians,
|
||||
so they are not references and no record is written for them.
|
||||
|
||||
**Name a place of publication as the publisher.** `(London, 1973)` says where
|
||||
a book was published and not by whom, so `container` stays empty. The place
|
||||
is still in `text`.
|
||||
|
||||
@@ -128,6 +128,18 @@ static NOT_A_TITLE: LazyLock<Regex> = LazyLock::new(|| {
|
||||
.expect("a valid pattern")
|
||||
});
|
||||
|
||||
/// A reference to chapter and verse: `Matthew 4:17`, `1 Peter 2:6-8`.
|
||||
///
|
||||
/// A book of the Bible is not a work in a bibliography — nobody is looking
|
||||
/// for the publisher of Galatians — and a page of them is what the notes of
|
||||
/// a theological book largely are.
|
||||
static VERSE: LazyLock<Regex> = LazyLock::new(|| {
|
||||
Regex::new(
|
||||
r"(?i)^(?:cf\.?|see|and)?\s*(?:[1-4]\s+)?\p{L}[\p{L}.]{2,14}\.?\s+\d{1,3}(?::\d{1,3}(?:[-–]\d{1,3})?)?\.?$",
|
||||
)
|
||||
.expect("a valid pattern")
|
||||
});
|
||||
|
||||
/// A page reference or a bracketed imprint: what a citation has and a remark
|
||||
/// about the argument does not.
|
||||
static CITATION_ANCHOR: LazyLock<Regex> = LazyLock::new(|| {
|
||||
@@ -216,6 +228,9 @@ pub fn one(text: &str, marker: Option<&str>) -> Option<Reference> {
|
||||
if !CITATION_SIGNAL.is_match(text) {
|
||||
return None;
|
||||
}
|
||||
if is_scripture(text) {
|
||||
return None;
|
||||
}
|
||||
// A note that runs on for six sentences with no imprint, no page
|
||||
// reference and no identifier is a remark about the argument. The LLM
|
||||
// path this replaces was told to skip those; a parser has to decide.
|
||||
@@ -436,6 +451,20 @@ fn strip_markup(text: &str) -> String {
|
||||
without_tags.replace(['*', '_'], "").trim().to_string()
|
||||
}
|
||||
|
||||
/// Whether an entry is chapter and verse and nothing else.
|
||||
///
|
||||
/// Several of them separated by semicolons is still a scripture reference
|
||||
/// and still not a work: `Cf. Deuteronomy 18:15-19; Isaiah 53; Acts 1:6`.
|
||||
fn is_scripture(text: &str) -> bool {
|
||||
let text = text.trim_start_matches(['.', ' ']);
|
||||
let parts: Vec<&str> = text
|
||||
.split(';')
|
||||
.map(str::trim)
|
||||
.filter(|part| !part.is_empty())
|
||||
.collect();
|
||||
!parts.is_empty() && parts.iter().all(|part| VERSE.is_match(part))
|
||||
}
|
||||
|
||||
/// Every identifier the entry carries, normalised.
|
||||
///
|
||||
/// Order is fixed rather than found: two entries carrying the same
|
||||
@@ -1075,6 +1104,26 @@ mod tests {
|
||||
assert_eq!(found.container, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn chapter_and_verse_is_not_a_work_in_a_bibliography() {
|
||||
for verse in [
|
||||
"Matthew 4:17",
|
||||
". Cf. Deuteronomy 18:15-19; Isaiah 53; Acts 1:6",
|
||||
"1 Peter 2:6-8",
|
||||
"Matthew 13:43; cf Exodus 34:29-35",
|
||||
] {
|
||||
assert!(one(verse, None).is_none(), "{verse}");
|
||||
}
|
||||
// A journal and its volume look similar and are not the same thing.
|
||||
assert!(
|
||||
one(
|
||||
"Altmann, M. 1951, A Study of Behaviour. Sociometry 14, 351-354.",
|
||||
None
|
||||
)
|
||||
.is_some()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_heading_or_a_page_number_is_not_a_reference() {
|
||||
for junk in ["Bibliography", "233", "Notes to pages 12-14", "see below"] {
|
||||
|
||||
@@ -249,7 +249,11 @@ fn strip_marker(raw: &str) -> Entry {
|
||||
let consumed = bare[..whole.end()].chars().count();
|
||||
let cut = from[consumed];
|
||||
return Entry {
|
||||
text: text[cut..].trim_start().to_string(),
|
||||
// `[4] . Smith, John` leaves the stop that belonged to the
|
||||
// marker sitting in front of the entry.
|
||||
text: text[cut..]
|
||||
.trim_start_matches(|c: char| ".) ".contains(c))
|
||||
.to_string(),
|
||||
marker: Some(found[1].to_string()),
|
||||
};
|
||||
}
|
||||
@@ -425,6 +429,13 @@ Another Anonymous Work. Cambridge, 2001.";
|
||||
assert_eq!(entry.text, "Smith, *Title*, p. 4.");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_stop_that_belonged_to_the_marker_does_not_start_the_entry() {
|
||||
let entry = strip_marker("[4] . Smith, John. *A Real Book*. Oxford, 1998.");
|
||||
assert_eq!(entry.marker.as_deref(), Some("4"));
|
||||
assert_eq!(entry.text, "Smith, John. *A Real Book*. Oxford, 1998.");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn an_entry_with_no_marker_keeps_all_of_itself() {
|
||||
let entry = strip_marker("Smith, John. The Title. Oxford, 1998.");
|
||||
|
||||
Reference in New Issue
Block a user