diff --git a/crates/citefind/src/parse.rs b/crates/citefind/src/parse.rs index be7c6b7..2337381 100644 --- a/crates/citefind/src/parse.rs +++ b/crates/citefind/src/parse.rs @@ -231,6 +231,14 @@ static ACKNOWLEDGEMENT: LazyLock = LazyLock::new(|| { .expect("a valid pattern") }); +/// How a translator or an editor signs a note of their own: an em dash and +/// their role, at the very end. `Latin: "nature of the thing." — Ed.` is a +/// gloss on the text in front of it and cites nothing. +static GLOSS_SIGNATURE: LazyLock = LazyLock::new(|| { + Regex::new(r"(?i)[—–-]{1,2}\s*(?:ed|tr|trans|transl|a\.\s*n|au)\.?\s*$") + .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 = LazyLock::new(|| { @@ -358,6 +366,7 @@ pub fn one(text: &str, marker: Option<&str>) -> Option { || BIOGRAPHY.is_match(text) || PRINT_FURNITURE.is_match(text) || ACKNOWLEDGEMENT.is_match(text) + || GLOSS_SIGNATURE.is_match(text) { return None; } @@ -481,6 +490,21 @@ pub fn one(text: &str, marker: Option<&str>) -> Option { if out.title.as_deref().is_some_and(str::is_empty) { out.title = None; } + + // `See R. Hirzel, Die Person (1914), p. 7.` reads as an author-date entry + // — the head is all capitalised words and the year is in brackets — and + // then yields no title, because the title is sitting inside what was + // taken for the names. A note that names a work is the better reading of + // the same line, and having a title is how you can tell. + if out.title.is_none() { + if let Some((names, title, container)) = note_form(text) { + if title.is_some() { + out.authors = names; + out.title = title; + out.container = container.or(out.container.take()); + } + } + } out.kind = kind(text, &out); Some(out) @@ -1483,6 +1507,22 @@ mod tests { assert_eq!(found.year, Some(2000)); } + #[test] + fn a_translators_note_signs_itself_and_cites_nothing() { + for gloss in [ + "Latin: \"nature of the thing.\" — Ed.", + "Reference to the wars between Athens and Sparta, 431-404 BC. — Ed.", + "Meaning here names, dates and numbers, in the usual sense. — Tr.", + ] { + assert!(one(gloss, None).is_none(), "{gloss}"); + } + // A note that cites a work is still a citation, sign-off or not. + let real = read("See R. Hirzel, Die Person (1914), p. 7."); + assert_eq!(real.authors, ["R. Hirzel"]); + assert_eq!(real.title.as_deref(), Some("Die Person")); + assert_eq!(real.year, Some(1914)); + } + #[test] fn a_short_note_names_a_work_without_a_year_or_a_publisher() { // The form a history book uses for every citation after the first: diff --git a/crates/citefind/src/split.rs b/crates/citefind/src/split.rs index 72e2df2..92be328 100644 --- a/crates/citefind/src/split.rs +++ b/crates/citefind/src/split.rs @@ -112,6 +112,11 @@ static ARROW_MARKER: LazyLock = LazyLock::new(|| { .expect("a valid pattern") }); +/// An HTML comment. Conversion leaves `` between list items and +/// `` where a page turned; neither is part of a reference. +static COMMENT: LazyLock = + LazyLock::new(|| Regex::new(r"").expect("a valid pattern")); + /// A bullet or a blockquote marker, which conversion puts in front of a note /// often enough to matter. A leading `*` is left alone: it opens an italic /// title as often as it opens a list. @@ -276,6 +281,7 @@ fn unnumbered(text: &str) -> Vec { /// further along survives. fn strip_marker(raw: &str) -> Entry { let text = cut_footer(&tidy(raw)); + let text = tidy(&COMMENT.replace_all(&text, " ")); let text = BULLET.replace(&text, "").to_string(); let (bare, from) = visible(&text, 160); @@ -517,6 +523,24 @@ Another Anonymous Work. Cambridge, 2001."; assert_eq!(entry.text, "Holquist, Making War, pp. 211-12."); } + #[test] + fn the_back_reference_marker_an_epub_conversion_leaves() { + let plain = strip_marker("\\[←788 \\]\u{a0} Krumbacher, Byz. Lit.-Gesch., p. 969."); + assert_eq!(plain.marker.as_deref(), Some("788")); + assert_eq!(plain.text, "Krumbacher, Byz. Lit.-Gesch., p. 969."); + + let linked = + strip_marker("\\[[←193](index_split_011.xhtml#citation-193) \\]\u{a0} Œd. Rex., 642."); + assert_eq!(linked.marker.as_deref(), Some("193")); + assert_eq!(linked.text, "Œd. Rex., 642."); + } + + #[test] + fn a_comment_conversion_left_behind_is_not_part_of_a_reference() { + let entry = strip_marker("1. Smith, *A Title* (Oxford, 1998). "); + assert_eq!(entry.text, "Smith, *A Title* (Oxford, 1998)."); + } + #[test] fn an_entry_with_no_marker_keeps_all_of_itself() { let entry = strip_marker("Smith, John. The Title. Oxford, 1998.");