holdings: a dash-led edition tail normalises like a bracketed one, so the catalogue's "Pinkerton - Deluxe Edition" finds the member who holds Pinkerton
This commit is contained in:
1 parent
1c66602b89
commit
aaacfc9ff5
1 file changed
+58
-3
@@ -87,10 +87,13 @@ fn key(username: &str) -> String {
|
|||||||
|
|
||||||
// ---------------------------------------------------------------- names
|
// ---------------------------------------------------------------- names
|
||||||
|
|
||||||
/// Bracketed chunks go — "(2019)", "[FLAC]", "{web}" — then only letters and
|
/// Bracketed chunks go — "(2019)", "[FLAC]", "{web}" — and so does a
|
||||||
/// digits remain, lowercased; a leading "the" goes too. "Sigur Rós" and
|
/// dash-led edition tail — "Pinkerton - Deluxe Edition", "Foo - EP" — then
|
||||||
/// "sigur ros" are not the same string here, and that is a known miss.
|
/// only letters and digits remain, lowercased; a leading "the" goes too.
|
||||||
|
/// "Sigur Rós" and "sigur ros" are not the same string here, and that is a
|
||||||
|
/// known miss.
|
||||||
pub(crate) fn norm(s: &str) -> String {
|
pub(crate) fn norm(s: &str) -> String {
|
||||||
|
let s = strip_edition_tail(s);
|
||||||
let mut out = String::with_capacity(s.len());
|
let mut out = String::with_capacity(s.len());
|
||||||
let mut depth = 0i32;
|
let mut depth = 0i32;
|
||||||
for c in s.chars() {
|
for c in s.chars() {
|
||||||
@@ -115,6 +118,41 @@ pub(crate) fn norm(s: &str) -> String {
|
|||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The catalogue spells an edition after a spaced dash where a folder would
|
||||||
|
/// bracket it — "Pinkerton - Deluxe Edition" is the gap card, "Pinkerton
|
||||||
|
/// (Deluxe Edition)" the folder — so a dash-led tail that reads as an
|
||||||
|
/// edition goes the way brackets do, and only that tail: "Boards of Canada -
|
||||||
|
/// Geogaddi" is a name with a dash in it and stays whole. Found 2026-09-09
|
||||||
|
/// when the deluxe card beside a marked Pinkerton carried no "has it".
|
||||||
|
fn strip_edition_tail(s: &str) -> &str {
|
||||||
|
let mut s = s.trim_end();
|
||||||
|
loop {
|
||||||
|
let Some((at, len)) = [" - ", " – ", " — "]
|
||||||
|
.iter()
|
||||||
|
.filter_map(|d| s.rfind(d).map(|i| (i, d.len())))
|
||||||
|
.max_by_key(|(i, _)| *i)
|
||||||
|
else {
|
||||||
|
return s;
|
||||||
|
};
|
||||||
|
let tail: String = s[at + len..]
|
||||||
|
.chars()
|
||||||
|
.filter(|c| c.is_alphanumeric())
|
||||||
|
.flat_map(|c| c.to_lowercase())
|
||||||
|
.collect();
|
||||||
|
if !is_edition_tail(&tail) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
s = s[..at].trim_end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_edition_tail(t: &str) -> bool {
|
||||||
|
matches!(t, "ep" | "single")
|
||||||
|
|| ["deluxe", "remaster", "edition", "expanded", "anniversary", "reissue", "bonus", "explicit"]
|
||||||
|
.iter()
|
||||||
|
.any(|w| t.contains(w))
|
||||||
|
}
|
||||||
|
|
||||||
fn is_disc_folder(s: &str) -> bool {
|
fn is_disc_folder(s: &str) -> bool {
|
||||||
let n: String = s.to_lowercase().chars().filter(|c| c.is_alphanumeric()).collect();
|
let n: String = s.to_lowercase().chars().filter(|c| c.is_alphanumeric()).collect();
|
||||||
for p in ["cd", "disc", "disk", "vol", "volume", "side"] {
|
for p in ["cd", "disc", "disk", "vol", "volume", "side"] {
|
||||||
@@ -352,4 +390,21 @@ mod tests {
|
|||||||
assert_eq!(norm("2000 - Spirit They're Gone Spirit They've Vanished"), "spirittheyregonespirittheyvevanished");
|
assert_eq!(norm("2000 - Spirit They're Gone Spirit They've Vanished"), "spirittheyregonespirittheyvevanished");
|
||||||
assert!(is_disc_folder("Disc 2") && is_disc_folder("cd1") && !is_disc_folder("Discovery"));
|
assert!(is_disc_folder("Disc 2") && is_disc_folder("cd1") && !is_disc_folder("Discovery"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dash_led_editions_go_the_way_brackets_do() {
|
||||||
|
assert_eq!(norm("Pinkerton - Deluxe Edition"), "pinkerton");
|
||||||
|
assert_eq!(norm("Pinkerton – Deluxe Edition"), "pinkerton");
|
||||||
|
assert_eq!(norm("Pinkerton — Deluxe Edition"), "pinkerton");
|
||||||
|
assert_eq!(norm("Pinkerton - Deluxe Edition (2010)"), "pinkerton");
|
||||||
|
assert_eq!(norm("Album - Deluxe Edition - Remastered"), "album");
|
||||||
|
assert_eq!(norm("Kid A - 2019 Remaster"), "kida");
|
||||||
|
assert_eq!(norm("Foo - EP"), "foo");
|
||||||
|
assert_eq!(norm("Foo - Single"), "foo");
|
||||||
|
assert_eq!(norm("Pinkerton (Deluxe Edition) [2010]"), norm("Pinkerton - Deluxe Edition"));
|
||||||
|
// A dash inside a name is not an edition.
|
||||||
|
assert_eq!(norm("Boards of Canada - Geogaddi"), "boardsofcanadageogaddi");
|
||||||
|
assert_eq!(norm("Album - Live"), "albumlive");
|
||||||
|
assert_eq!(norm("1996 - Expert Knob Twiddlers"), "expertknobtwiddlers");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user