mirror of
https://git.pumpin.online/funkpower/catena.git
synced 2026-10-23 03:07:13 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
90fb977a10 | ||
|
|
05b712d084 |
Generated
+26
-26
@@ -101,7 +101,7 @@ checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "avplan"
|
name = "avplan"
|
||||||
version = "0.2.1"
|
version = "0.2.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"catena-cli",
|
"catena-cli",
|
||||||
"clap",
|
"clap",
|
||||||
@@ -126,7 +126,7 @@ checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bibclean"
|
name = "bibclean"
|
||||||
version = "0.2.1"
|
version = "0.2.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"catena-cli",
|
"catena-cli",
|
||||||
"clap",
|
"clap",
|
||||||
@@ -143,7 +143,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bibfetch"
|
name = "bibfetch"
|
||||||
version = "0.2.1"
|
version = "0.2.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"catena-cli",
|
"catena-cli",
|
||||||
"clap",
|
"clap",
|
||||||
@@ -196,7 +196,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bookmeta"
|
name = "bookmeta"
|
||||||
version = "0.2.1"
|
version = "0.2.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"catena-cli",
|
"catena-cli",
|
||||||
"clap",
|
"clap",
|
||||||
@@ -210,7 +210,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "booksniff"
|
name = "booksniff"
|
||||||
version = "0.2.1"
|
version = "0.2.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"catena-cli",
|
"catena-cli",
|
||||||
"clap",
|
"clap",
|
||||||
@@ -250,7 +250,7 @@ checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "catena"
|
name = "catena"
|
||||||
version = "0.2.1"
|
version = "0.2.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bibclean",
|
"bibclean",
|
||||||
"bibfetch",
|
"bibfetch",
|
||||||
@@ -277,7 +277,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "catena-cli"
|
name = "catena-cli"
|
||||||
version = "0.2.1"
|
version = "0.2.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"clap_mangen",
|
"clap_mangen",
|
||||||
@@ -312,7 +312,7 @@ checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chunkmd"
|
name = "chunkmd"
|
||||||
version = "0.2.1"
|
version = "0.2.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"catena-cli",
|
"catena-cli",
|
||||||
"clap",
|
"clap",
|
||||||
@@ -334,7 +334,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "citefind"
|
name = "citefind"
|
||||||
version = "0.2.1"
|
version = "0.2.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"catena-cli",
|
"catena-cli",
|
||||||
"chunkmd",
|
"chunkmd",
|
||||||
@@ -399,7 +399,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "colophon"
|
name = "colophon"
|
||||||
version = "0.2.1"
|
version = "0.2.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bibclean",
|
"bibclean",
|
||||||
"catena-cli",
|
"catena-cli",
|
||||||
@@ -448,7 +448,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "corpus-core"
|
name = "corpus-core"
|
||||||
version = "0.2.1"
|
version = "0.2.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"schemars",
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -492,7 +492,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cuekit"
|
name = "cuekit"
|
||||||
version = "0.2.1"
|
version = "0.2.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"corpus-core",
|
"corpus-core",
|
||||||
"regex",
|
"regex",
|
||||||
@@ -504,7 +504,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cuenorm"
|
name = "cuenorm"
|
||||||
version = "0.2.1"
|
version = "0.2.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"catena-cli",
|
"catena-cli",
|
||||||
"clap",
|
"clap",
|
||||||
@@ -514,7 +514,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cuepack"
|
name = "cuepack"
|
||||||
version = "0.2.1"
|
version = "0.2.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"catena-cli",
|
"catena-cli",
|
||||||
"clap",
|
"clap",
|
||||||
@@ -525,7 +525,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cueseg"
|
name = "cueseg"
|
||||||
version = "0.2.1"
|
version = "0.2.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"catena-cli",
|
"catena-cli",
|
||||||
"clap",
|
"clap",
|
||||||
@@ -612,7 +612,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "emb"
|
name = "emb"
|
||||||
version = "0.2.1"
|
version = "0.2.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"catena-cli",
|
"catena-cli",
|
||||||
"clap",
|
"clap",
|
||||||
@@ -876,7 +876,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idnorm"
|
name = "idnorm"
|
||||||
version = "0.2.1"
|
version = "0.2.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bibclean",
|
"bibclean",
|
||||||
"catena-cli",
|
"catena-cli",
|
||||||
@@ -942,7 +942,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "langid"
|
name = "langid"
|
||||||
version = "0.2.1"
|
version = "0.2.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"catena-cli",
|
"catena-cli",
|
||||||
"clap",
|
"clap",
|
||||||
@@ -1022,7 +1022,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mdscrub"
|
name = "mdscrub"
|
||||||
version = "0.2.1"
|
version = "0.2.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"catena-cli",
|
"catena-cli",
|
||||||
"clap",
|
"clap",
|
||||||
@@ -1034,7 +1034,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mdsplit"
|
name = "mdsplit"
|
||||||
version = "0.2.1"
|
version = "0.2.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"catena-cli",
|
"catena-cli",
|
||||||
"clap",
|
"clap",
|
||||||
@@ -1113,7 +1113,7 @@ checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pdfgutter"
|
name = "pdfgutter"
|
||||||
version = "0.2.1"
|
version = "0.2.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"catena-cli",
|
"catena-cli",
|
||||||
"clap",
|
"clap",
|
||||||
@@ -1126,7 +1126,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pdftriage"
|
name = "pdftriage"
|
||||||
version = "0.2.1"
|
version = "0.2.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"catena-cli",
|
"catena-cli",
|
||||||
"clap",
|
"clap",
|
||||||
@@ -1370,7 +1370,7 @@ checksum = "323c417e1d9665a65b263ec744ba09030cfb277e9daa0b018a4ab62e57bc8189"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rrf"
|
name = "rrf"
|
||||||
version = "0.2.1"
|
version = "0.2.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"catena-cli",
|
"catena-cli",
|
||||||
"clap",
|
"clap",
|
||||||
@@ -1517,7 +1517,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "seriesof"
|
name = "seriesof"
|
||||||
version = "0.2.1"
|
version = "0.2.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"catena-cli",
|
"catena-cli",
|
||||||
"clap",
|
"clap",
|
||||||
@@ -1634,7 +1634,7 @@ checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "textkit"
|
name = "textkit"
|
||||||
version = "0.2.1"
|
version = "0.2.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"regex",
|
"regex",
|
||||||
"tiktoken-rs",
|
"tiktoken-rs",
|
||||||
@@ -1724,7 +1724,7 @@ checksum = "fd3ca314f692efd6c868f8408f53fe444634a845f96c028b97d35f6a1f79f0ee"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tocfind"
|
name = "tocfind"
|
||||||
version = "0.2.1"
|
version = "0.2.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"catena-cli",
|
"catena-cli",
|
||||||
"clap",
|
"clap",
|
||||||
|
|||||||
+27
-27
@@ -3,39 +3,39 @@ resolver = "3"
|
|||||||
members = ["crates/*"]
|
members = ["crates/*"]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.2.1"
|
version = "0.2.3"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
rust-version = "1.85"
|
rust-version = "1.85"
|
||||||
license = "MPL-2.0"
|
license = "MPL-2.0"
|
||||||
repository = "https://git.pumpin.online/funkpower/catena"
|
repository = "https://git.pumpin.online/funkpower/catena"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
catena-cli = { path = "crates/catena-cli", version = "0.2.1" }
|
catena-cli = { path = "crates/catena-cli", version = "0.2.3" }
|
||||||
corpus-core = { path = "crates/corpus-core", version = "0.2.1" }
|
corpus-core = { path = "crates/corpus-core", version = "0.2.3" }
|
||||||
cuekit = { path = "crates/cuekit", version = "0.2.1" }
|
cuekit = { path = "crates/cuekit", version = "0.2.3" }
|
||||||
textkit = { path = "crates/textkit", version = "0.2.1" }
|
textkit = { path = "crates/textkit", version = "0.2.3" }
|
||||||
chunkmd = { path = "crates/chunkmd", version = "0.2.1" }
|
chunkmd = { path = "crates/chunkmd", version = "0.2.3" }
|
||||||
mdscrub = { path = "crates/mdscrub", version = "0.2.1" }
|
mdscrub = { path = "crates/mdscrub", version = "0.2.3" }
|
||||||
mdsplit = { path = "crates/mdsplit", version = "0.2.1" }
|
mdsplit = { path = "crates/mdsplit", version = "0.2.3" }
|
||||||
pdftriage = { path = "crates/pdftriage", version = "0.2.1" }
|
pdftriage = { path = "crates/pdftriage", version = "0.2.3" }
|
||||||
cuenorm = { path = "crates/cuenorm", version = "0.2.1" }
|
cuenorm = { path = "crates/cuenorm", version = "0.2.3" }
|
||||||
cueseg = { path = "crates/cueseg", version = "0.2.1" }
|
cueseg = { path = "crates/cueseg", version = "0.2.3" }
|
||||||
rrf = { path = "crates/rrf", version = "0.2.1" }
|
rrf = { path = "crates/rrf", version = "0.2.3" }
|
||||||
cuepack = { path = "crates/cuepack", version = "0.2.1" }
|
cuepack = { path = "crates/cuepack", version = "0.2.3" }
|
||||||
bibclean = { path = "crates/bibclean", version = "0.2.1" }
|
bibclean = { path = "crates/bibclean", version = "0.2.3" }
|
||||||
avplan = { path = "crates/avplan", version = "0.2.1" }
|
avplan = { path = "crates/avplan", version = "0.2.3" }
|
||||||
pdfgutter = { path = "crates/pdfgutter", version = "0.2.1" }
|
pdfgutter = { path = "crates/pdfgutter", version = "0.2.3" }
|
||||||
catena = { path = "crates/bindings", version = "0.2.1" }
|
catena = { path = "crates/bindings", version = "0.2.3" }
|
||||||
seriesof = { path = "crates/seriesof", version = "0.2.1" }
|
seriesof = { path = "crates/seriesof", version = "0.2.3" }
|
||||||
idnorm = { path = "crates/idnorm", version = "0.2.1" }
|
idnorm = { path = "crates/idnorm", version = "0.2.3" }
|
||||||
bibfetch = { path = "crates/bibfetch", version = "0.2.1" }
|
bibfetch = { path = "crates/bibfetch", version = "0.2.3" }
|
||||||
bookmeta = { path = "crates/bookmeta", version = "0.2.1" }
|
bookmeta = { path = "crates/bookmeta", version = "0.2.3" }
|
||||||
langid = { path = "crates/langid", version = "0.2.1" }
|
langid = { path = "crates/langid", version = "0.2.3" }
|
||||||
tocfind = { path = "crates/tocfind", version = "0.2.1" }
|
tocfind = { path = "crates/tocfind", version = "0.2.3" }
|
||||||
booksniff = { path = "crates/booksniff", version = "0.2.1" }
|
booksniff = { path = "crates/booksniff", version = "0.2.3" }
|
||||||
citefind = { path = "crates/citefind", version = "0.2.1" }
|
citefind = { path = "crates/citefind", version = "0.2.3" }
|
||||||
colophon = { path = "crates/colophon", version = "0.2.1" }
|
colophon = { path = "crates/colophon", version = "0.2.3" }
|
||||||
emb = { path = "crates/emb", version = "0.2.1" }
|
emb = { path = "crates/emb", version = "0.2.3" }
|
||||||
|
|
||||||
clap = { version = "4", features = ["derive"] }
|
clap = { version = "4", features = ["derive"] }
|
||||||
clap_mangen = "0.3"
|
clap_mangen = "0.3"
|
||||||
|
|||||||
@@ -67,7 +67,19 @@ pub fn title_case(title: &str) -> String {
|
|||||||
.to_lowercase()
|
.to_lowercase()
|
||||||
.trim_end_matches(['.', ',', ':', ';', '!', '?', ')', ']', '"', '\''])
|
.trim_end_matches(['.', ',', ':', ';', '!', '?', ')', ']', '"', '\''])
|
||||||
.to_string();
|
.to_string();
|
||||||
if SMALL_WORDS.binary_search(&core.as_str()).is_ok() && at > 0 && at < last {
|
// A small word stays small in the middle of a title, but not
|
||||||
|
// where a title actually starts. A colon starts a subtitle, and
|
||||||
|
// "Aesthetic in Kant: a Critique" is the giveaway that the rule
|
||||||
|
// was only ever counting from the beginning of the whole string.
|
||||||
|
let opens_a_subtitle = at > 0
|
||||||
|
&& words[at - 1]
|
||||||
|
.trim_end_matches(['"', '\'', ')', ']'])
|
||||||
|
.ends_with([':', ';', '?', '!', '.']);
|
||||||
|
if SMALL_WORDS.binary_search(&core.as_str()).is_ok()
|
||||||
|
&& at > 0
|
||||||
|
&& at < last
|
||||||
|
&& !opens_a_subtitle
|
||||||
|
{
|
||||||
return word.to_lowercase();
|
return word.to_lowercase();
|
||||||
}
|
}
|
||||||
let lowered = word.to_lowercase();
|
let lowered = word.to_lowercase();
|
||||||
@@ -218,3 +230,35 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod subtitle_case_tests {
|
||||||
|
use super::title_case;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn a_subtitle_starts_with_a_capital() {
|
||||||
|
// The rule counted small words from the start of the string, so every
|
||||||
|
// subtitle beginning "A", "The" or "Of" was set lower case.
|
||||||
|
assert_eq!(
|
||||||
|
title_case("AESTHETIC IN KANT: A CRITIQUE"),
|
||||||
|
"Aesthetic in Kant: A Critique"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
title_case("BORN FIGHTING: THE SCOTS-IRISH"),
|
||||||
|
"Born Fighting: The Scots-Irish"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
title_case("A HISTORY: AN INTRODUCTION TO IT"),
|
||||||
|
"A History: An Introduction to It"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn a_small_word_in_the_middle_is_still_small() {
|
||||||
|
assert_eq!(
|
||||||
|
title_case("THE RISE AND FALL OF THE THIRD REICH"),
|
||||||
|
"The Rise and Fall of the Third Reich"
|
||||||
|
);
|
||||||
|
assert_eq!(title_case("WAR OF THE WORLDS"), "War of the Worlds");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -260,9 +260,14 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn an_underscored_title_is_cleaned_before_it_is_cased() {
|
fn an_underscored_title_is_cleaned_before_it_is_cased() {
|
||||||
let cleaned = clean(&book("THE FALL_ AND THE RISE_txt", "Arendt, Hannah"));
|
let cleaned = clean(&book("THE FALL_ AND THE RISE_txt", "Arendt, Hannah"));
|
||||||
|
// "And" is capitalised because the colon starts a subtitle, and the
|
||||||
|
// first word of one is capitalised however small it is. This asserted
|
||||||
|
// "and" until the rule was found to be counting small words from the
|
||||||
|
// start of the whole string, which set every subtitle opening "A",
|
||||||
|
// "The" or "An" in lower case.
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cleaned.book.title.as_deref(),
|
cleaned.book.title.as_deref(),
|
||||||
Some("The Fall: and the Rise")
|
Some("The Fall: And the Rise")
|
||||||
);
|
);
|
||||||
assert_eq!(cleaned.changes.len(), 2);
|
assert_eq!(cleaned.changes.len(), 2);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,29 @@ static LIFESPAN: LazyLock<Regex> = LazyLock::new(|| {
|
|||||||
static BARE_DATE: LazyLock<Regex> =
|
static BARE_DATE: LazyLock<Regex> =
|
||||||
LazyLock::new(|| Regex::new(r"(?i)^\d{1,4}\s*(bc|ad|bce|ce)?\.?$").expect("a valid pattern"));
|
LazyLock::new(|| Regex::new(r"(?i)^\d{1,4}\s*(bc|ad|bce|ce)?\.?$").expect("a valid pattern"));
|
||||||
/// `Copyright © 2013 by`, `\u{a9} 2013 Richard Swinburne`, `Copyright 1971 by`.
|
/// `Copyright © 2013 by`, `\u{a9} 2013 Richard Swinburne`, `Copyright 1971 by`.
|
||||||
|
/// `1. General Remarks`, `2 James W. McAllister` — a numbered heading.
|
||||||
|
static NUMBERED_HEADING: LazyLock<Regex> =
|
||||||
|
LazyLock::new(|| Regex::new(r"^\s*\d+\s*[.)]\s+\S|^\s*\d+\s{2,}\S").expect("a valid pattern"));
|
||||||
|
/// `5222 What Is This`, `827 North Fourth Street` — a number that is not a
|
||||||
|
/// year, leading a line.
|
||||||
|
static LEADING_NUMBER: LazyLock<Regex> =
|
||||||
|
LazyLock::new(|| Regex::new(r"^\s*(\d{1,5})\s+\S").expect("a valid pattern"));
|
||||||
|
/// `Page xxxvi`, `Chapter I`, `Fig. 3` — a marker, not a name.
|
||||||
|
static MARKER: LazyLock<Regex> = LazyLock::new(|| {
|
||||||
|
Regex::new(
|
||||||
|
r"(?i)^\s*(page|pages|p\.|pp\.|fig\.|figure|plate|chapter|ch\.|section|part)\s+[\divxlcm]",
|
||||||
|
)
|
||||||
|
.expect("a valid pattern")
|
||||||
|
});
|
||||||
|
/// `Sidebottom, Harry. Ancient warfare` — a bibliography entry, which front
|
||||||
|
/// matter prints in its cataloguing block and in its further reading.
|
||||||
|
static CATALOGUE_ENTRY: LazyLock<Regex> = LazyLock::new(|| {
|
||||||
|
Regex::new(r"^[A-Z][A-Za-z'\-]+,\s+[A-Z][A-Za-z'.\-]*\.\s+\S").expect("a valid pattern")
|
||||||
|
});
|
||||||
|
/// `To Mackenzie,` — a dedication, set alone on its own page.
|
||||||
|
static DEDICATION: LazyLock<Regex> = LazyLock::new(|| {
|
||||||
|
Regex::new(r"(?i)^\s*(to|for|in memory of)\s+\S.*,\s*$").expect("a valid pattern")
|
||||||
|
});
|
||||||
static COPYRIGHT_NOTICE: LazyLock<Regex> = LazyLock::new(|| {
|
static COPYRIGHT_NOTICE: LazyLock<Regex> = LazyLock::new(|| {
|
||||||
// The year need not follow the symbol directly: "(c) Alfredo Ferrarin
|
// The year need not follow the symbol directly: "(c) Alfredo Ferrarin
|
||||||
// 2004" puts the holder between them, and was read as a title.
|
// 2004" puts the holder between them, and was read as a title.
|
||||||
@@ -79,10 +102,13 @@ copenhagen|stockholm|moscow|beijing|tokyo|delhi|nairobi)\b[\s,·•|and]*",
|
|||||||
static STRUCTURAL: &[&str] = &[
|
static STRUCTURAL: &[&str] = &[
|
||||||
"abbreviations",
|
"abbreviations",
|
||||||
"about the author",
|
"about the author",
|
||||||
|
"abstract",
|
||||||
"acknowledgements",
|
"acknowledgements",
|
||||||
"acknowledgments",
|
"acknowledgments",
|
||||||
"afterword",
|
"afterword",
|
||||||
"appendix",
|
"appendix",
|
||||||
|
"author",
|
||||||
|
"authors",
|
||||||
"bibliography",
|
"bibliography",
|
||||||
"contents",
|
"contents",
|
||||||
"dedication",
|
"dedication",
|
||||||
@@ -95,6 +121,7 @@ static STRUCTURAL: &[&str] = &[
|
|||||||
"illustrations",
|
"illustrations",
|
||||||
"index",
|
"index",
|
||||||
"introduction",
|
"introduction",
|
||||||
|
"keywords",
|
||||||
"list of contributors",
|
"list of contributors",
|
||||||
"list of illustrations",
|
"list of illustrations",
|
||||||
"maps",
|
"maps",
|
||||||
@@ -102,7 +129,9 @@ static STRUCTURAL: &[&str] = &[
|
|||||||
"postscript",
|
"postscript",
|
||||||
"preface",
|
"preface",
|
||||||
"prologue",
|
"prologue",
|
||||||
|
"subtitle",
|
||||||
"table of contents",
|
"table of contents",
|
||||||
|
"title",
|
||||||
"title page",
|
"title page",
|
||||||
"translator's note",
|
"translator's note",
|
||||||
];
|
];
|
||||||
@@ -182,6 +211,22 @@ fn is_furniture(line: &str) -> bool {
|
|||||||
}
|
}
|
||||||
// Sentences a copyright page sets, which are not notices and so not caught
|
// Sentences a copyright page sets, which are not notices and so not caught
|
||||||
// by the notice pattern.
|
// by the notice pattern.
|
||||||
|
if NUMBERED_HEADING.is_match(t) || MARKER.is_match(t) || CATALOGUE_ENTRY.is_match(t) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// A line opening with a number that is not a year. "5222 What Is This" and
|
||||||
|
// "827 North Fourth Street" are a stray folio and an address; "1984
|
||||||
|
// Revisited" is a book, and the difference is whether the number could be
|
||||||
|
// the year of one.
|
||||||
|
if let Some(c) = LEADING_NUMBER.captures(t) {
|
||||||
|
let n: u32 = c[1].parse().unwrap_or(0);
|
||||||
|
if !(1000..=2099).contains(&n) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if DEDICATION.is_match(t) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
let lower = t.to_lowercase();
|
let lower = t.to_lowercase();
|
||||||
for phrase in [
|
for phrase in [
|
||||||
"moral rights of the author",
|
"moral rights of the author",
|
||||||
@@ -496,3 +541,54 @@ mod conversion_tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod review_pile_tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
/// Everything here was proposed as a title by a real run over this
|
||||||
|
/// library, and sat in the review queue waiting for a person to say no.
|
||||||
|
#[test]
|
||||||
|
fn what_the_review_pile_was_full_of() {
|
||||||
|
for line in [
|
||||||
|
"1. General Remarks",
|
||||||
|
"2 James W. McAllister",
|
||||||
|
"5222 What Is This",
|
||||||
|
"827 North Fourth Street",
|
||||||
|
"Page xxxvi",
|
||||||
|
"Page xxxviii",
|
||||||
|
"Chapter I",
|
||||||
|
"title",
|
||||||
|
"Sidebottom, Harry. Ancient warfare",
|
||||||
|
"To Mackenzie,",
|
||||||
|
] {
|
||||||
|
assert!(
|
||||||
|
is_structural(line) || is_furniture(line),
|
||||||
|
"still read as a title: {line:?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// And none of it catches a book. The numbers are the delicate part: a
|
||||||
|
/// year can open a title, and a folio cannot.
|
||||||
|
#[test]
|
||||||
|
fn a_book_is_still_a_book() {
|
||||||
|
for line in [
|
||||||
|
"1984 Revisited",
|
||||||
|
"1914: The Year the World Ended",
|
||||||
|
"Chapter and Verse",
|
||||||
|
"Part of the Furniture",
|
||||||
|
"To Kill a Mockingbird",
|
||||||
|
"For Whom the Bell Tolls",
|
||||||
|
"The Title of This Book",
|
||||||
|
"Pages from a Cold Island",
|
||||||
|
"Sections of a Broken Whole",
|
||||||
|
"In Memory of Bread",
|
||||||
|
] {
|
||||||
|
assert!(
|
||||||
|
!(is_structural(line) || is_furniture(line)),
|
||||||
|
"rejected a real title: {line:?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user